From e03d72b99e4027504ada134bf1804d6ea792b206 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 9 Jan 2006 18:34:08 -0800 Subject: [PATCH] drivers/net/sk98lin/: possible cleanups This patch contains the following possible cleanups: - make needlessly global functions static - remove unused code Signed-off-by: Adrian Bunk Cc: Stephen Hemminger Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/sk98lin/h/skaddr.h | 48 ---- drivers/net/sk98lin/h/skcsum.h | 6 - drivers/net/sk98lin/h/skgeinit.h | 56 ----- drivers/net/sk98lin/h/skgepnmi.h | 4 - drivers/net/sk98lin/h/skgesirq.h | 1 - drivers/net/sk98lin/h/ski2c.h | 3 - drivers/net/sk98lin/h/skvpd.h | 15 -- drivers/net/sk98lin/skaddr.c | 35 ++- drivers/net/sk98lin/skgeinit.c | 148 +------------ drivers/net/sk98lin/skgemib.c | 7 - drivers/net/sk98lin/skgepnmi.c | 153 +------------ drivers/net/sk98lin/skgesirq.c | 24 +- drivers/net/sk98lin/ski2c.c | 6 +- drivers/net/sk98lin/sklm80.c | 72 ------ drivers/net/sk98lin/skrlmt.c | 1 - drivers/net/sk98lin/skvpd.c | 108 +-------- drivers/net/sk98lin/skxmac2.c | 461 +-------------------------------------- 17 files changed, 40 insertions(+), 1108 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sk98lin/h/skaddr.h b/drivers/net/sk98lin/h/skaddr.h index 3a2ea4a4b53..423ad063d09 100644 --- a/drivers/net/sk98lin/h/skaddr.h +++ b/drivers/net/sk98lin/h/skaddr.h @@ -236,18 +236,6 @@ extern int SkAddrMcClear( SK_U32 PortNumber, int Flags); -extern int SkAddrXmacMcClear( - SK_AC *pAC, - SK_IOC IoC, - SK_U32 PortNumber, - int Flags); - -extern int SkAddrGmacMcClear( - SK_AC *pAC, - SK_IOC IoC, - SK_U32 PortNumber, - int Flags); - extern int SkAddrMcAdd( SK_AC *pAC, SK_IOC IoC, @@ -255,35 +243,11 @@ extern int SkAddrMcAdd( SK_MAC_ADDR *pMc, int Flags); -extern int SkAddrXmacMcAdd( - SK_AC *pAC, - SK_IOC IoC, - SK_U32 PortNumber, - SK_MAC_ADDR *pMc, - int Flags); - -extern int SkAddrGmacMcAdd( - SK_AC *pAC, - SK_IOC IoC, - SK_U32 PortNumber, - SK_MAC_ADDR *pMc, - int Flags); - extern int SkAddrMcUpdate( SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber); -extern int SkAddrXmacMcUpdate( - SK_AC *pAC, - SK_IOC IoC, - SK_U32 PortNumber); - -extern int SkAddrGmacMcUpdate( - SK_AC *pAC, - SK_IOC IoC, - SK_U32 PortNumber); - extern int SkAddrOverride( SK_AC *pAC, SK_IOC IoC, @@ -297,18 +261,6 @@ extern int SkAddrPromiscuousChange( SK_U32 PortNumber, int NewPromMode); -extern int SkAddrXmacPromiscuousChange( - SK_AC *pAC, - SK_IOC IoC, - SK_U32 PortNumber, - int NewPromMode); - -extern int SkAddrGmacPromiscuousChange( - SK_AC *pAC, - SK_IOC IoC, - SK_U32 PortNumber, - int NewPromMode); - #ifndef SK_SLIM extern int SkAddrSwap( SK_AC *pAC, diff --git a/drivers/net/sk98lin/h/skcsum.h b/drivers/net/sk98lin/h/skcsum.h index 2b94adb9333..6e256bd9a28 100644 --- a/drivers/net/sk98lin/h/skcsum.h +++ b/drivers/net/sk98lin/h/skcsum.h @@ -203,12 +203,6 @@ extern SKCS_STATUS SkCsGetReceiveInfo( unsigned Checksum2, int NetNumber); -extern void SkCsGetSendInfo( - SK_AC *pAc, - void *pIpHeader, - SKCS_PACKET_INFO *pPacketInfo, - int NetNumber); - extern void SkCsSetReceiveFlags( SK_AC *pAc, unsigned ReceiveFlags, diff --git a/drivers/net/sk98lin/h/skgeinit.h b/drivers/net/sk98lin/h/skgeinit.h index 184f47c5a60..143e635ec24 100644 --- a/drivers/net/sk98lin/h/skgeinit.h +++ b/drivers/net/sk98lin/h/skgeinit.h @@ -464,12 +464,6 @@ typedef struct s_GeInit { /* * public functions in skgeinit.c */ -extern void SkGePollRxD( - SK_AC *pAC, - SK_IOC IoC, - int Port, - SK_BOOL PollRxD); - extern void SkGePollTxD( SK_AC *pAC, SK_IOC IoC, @@ -522,10 +516,6 @@ extern void SkGeXmitLED( int Led, int Mode); -extern void SkGeInitRamIface( - SK_AC *pAC, - SK_IOC IoC); - extern int SkGeInitAssignRamToQueues( SK_AC *pAC, int ActivePort, @@ -549,11 +539,6 @@ extern void SkMacHardRst( SK_IOC IoC, int Port); -extern void SkMacClearRst( - SK_AC *pAC, - SK_IOC IoC, - int Port); - extern void SkXmInitMac( SK_AC *pAC, SK_IOC IoC, @@ -580,11 +565,6 @@ extern void SkMacFlushTxFifo( SK_IOC IoC, int Port); -extern void SkMacFlushRxFifo( - SK_AC *pAC, - SK_IOC IoC, - int Port); - extern void SkMacIrq( SK_AC *pAC, SK_IOC IoC, @@ -601,12 +581,6 @@ extern void SkMacAutoNegLipaPhy( int Port, SK_U16 IStatus); -extern void SkMacSetRxTxEn( - SK_AC *pAC, - SK_IOC IoC, - int Port, - int Para); - extern int SkMacRxTxEnable( SK_AC *pAC, SK_IOC IoC, @@ -659,16 +633,6 @@ extern void SkXmClrExactAddr( int StartNum, int StopNum); -extern void SkXmInitDupMd( - SK_AC *pAC, - SK_IOC IoC, - int Port); - -extern void SkXmInitPauseMd( - SK_AC *pAC, - SK_IOC IoC, - int Port); - extern void SkXmAutoNegLipaXmac( SK_AC *pAC, SK_IOC IoC, @@ -729,17 +693,6 @@ extern int SkGmCableDiagStatus( int Port, SK_BOOL StartTest); -extern int SkGmEnterLowPowerMode( - SK_AC *pAC, - SK_IOC IoC, - int Port, - SK_U8 Mode); - -extern int SkGmLeaveLowPowerMode( - SK_AC *pAC, - SK_IOC IoC, - int Port); - #ifdef SK_DIAG extern void SkGePhyRead( SK_AC *pAC, @@ -782,7 +735,6 @@ extern void SkXmSendCont( /* * public functions in skgeinit.c */ -extern void SkGePollRxD(); extern void SkGePollTxD(); extern void SkGeYellowLED(); extern int SkGeCfgSync(); @@ -792,7 +744,6 @@ extern int SkGeInit(); extern void SkGeDeInit(); extern int SkGeInitPort(); extern void SkGeXmitLED(); -extern void SkGeInitRamIface(); extern int SkGeInitAssignRamToQueues(); /* @@ -801,18 +752,15 @@ extern int SkGeInitAssignRamToQueues(); extern void SkMacRxTxDisable(); extern void SkMacSoftRst(); extern void SkMacHardRst(); -extern void SkMacClearRst(); extern void SkMacInitPhy(); extern int SkMacRxTxEnable(); extern void SkMacPromiscMode(); extern void SkMacHashing(); extern void SkMacIrqDisable(); extern void SkMacFlushTxFifo(); -extern void SkMacFlushRxFifo(); extern void SkMacIrq(); extern int SkMacAutoNegDone(); extern void SkMacAutoNegLipaPhy(); -extern void SkMacSetRxTxEn(); extern void SkXmInitMac(); extern void SkXmPhyRead(); extern void SkXmPhyWrite(); @@ -820,8 +768,6 @@ extern void SkGmInitMac(); extern void SkGmPhyRead(); extern void SkGmPhyWrite(); extern void SkXmClrExactAddr(); -extern void SkXmInitDupMd(); -extern void SkXmInitPauseMd(); extern void SkXmAutoNegLipaXmac(); extern int SkXmUpdateStats(); extern int SkGmUpdateStats(); @@ -832,8 +778,6 @@ extern int SkGmResetCounter(); extern int SkXmOverflowStatus(); extern int SkGmOverflowStatus(); extern int SkGmCableDiagStatus(); -extern int SkGmEnterLowPowerMode(); -extern int SkGmLeaveLowPowerMode(); #ifdef SK_DIAG extern void SkGePhyRead(); diff --git a/drivers/net/sk98lin/h/skgepnmi.h b/drivers/net/sk98lin/h/skgepnmi.h index 3b2773e6f82..1ed214ccb25 100644 --- a/drivers/net/sk98lin/h/skgepnmi.h +++ b/drivers/net/sk98lin/h/skgepnmi.h @@ -946,10 +946,6 @@ typedef struct s_PnmiData { * Function prototypes */ extern int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int Level); -extern int SkPnmiGetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void* pBuf, - unsigned int* pLen, SK_U32 Instance, SK_U32 NetIndex); -extern int SkPnmiPreSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, - void* pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); extern int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void* pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); extern int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void* pBuf, diff --git a/drivers/net/sk98lin/h/skgesirq.h b/drivers/net/sk98lin/h/skgesirq.h index b486bd9b662..3eec6274e41 100644 --- a/drivers/net/sk98lin/h/skgesirq.h +++ b/drivers/net/sk98lin/h/skgesirq.h @@ -105,7 +105,6 @@ extern void SkGeSirqIsr(SK_AC *pAC, SK_IOC IoC, SK_U32 Istatus); extern int SkGeSirqEvent(SK_AC *pAC, SK_IOC IoC, SK_U32 Event, SK_EVPARA Para); -extern void SkHWLinkUp(SK_AC *pAC, SK_IOC IoC, int Port); extern void SkHWLinkDown(SK_AC *pAC, SK_IOC IoC, int Port); #endif /* _INC_SKGESIRQ_H_ */ diff --git a/drivers/net/sk98lin/h/ski2c.h b/drivers/net/sk98lin/h/ski2c.h index 598bb42ccc3..6a63f4a15de 100644 --- a/drivers/net/sk98lin/h/ski2c.h +++ b/drivers/net/sk98lin/h/ski2c.h @@ -162,9 +162,6 @@ typedef struct s_I2c { } SK_I2C; extern int SkI2cInit(SK_AC *pAC, SK_IOC IoC, int Level); -extern int SkI2cWrite(SK_AC *pAC, SK_IOC IoC, SK_U32 Data, int Dev, int Size, - int Reg, int Burst); -extern int SkI2cReadSensor(SK_AC *pAC, SK_IOC IoC, SK_SENSOR *pSen); #ifdef SK_DIAG extern SK_U32 SkI2cRead(SK_AC *pAC, SK_IOC IoC, int Dev, int Size, int Reg, int Burst); diff --git a/drivers/net/sk98lin/h/skvpd.h b/drivers/net/sk98lin/h/skvpd.h index daa9a8d154f..fdd9e48e804 100644 --- a/drivers/net/sk98lin/h/skvpd.h +++ b/drivers/net/sk98lin/h/skvpd.h @@ -183,14 +183,6 @@ extern SK_U32 VpdReadDWord( int addr); #endif /* SKDIAG */ -extern int VpdSetupPara( - SK_AC *pAC, - const char *key, - const char *buf, - int len, - int type, - int op); - extern SK_VPD_STATUS *VpdStat( SK_AC *pAC, SK_IOC IoC); @@ -227,11 +219,6 @@ extern int VpdUpdate( SK_AC *pAC, SK_IOC IoC); -extern void VpdErrLog( - SK_AC *pAC, - SK_IOC IoC, - char *msg); - #ifdef SKDIAG extern int VpdReadBlock( SK_AC *pAC, @@ -249,7 +236,6 @@ extern int VpdWriteBlock( #endif /* SKDIAG */ #else /* SK_KR_PROTO */ extern SK_U32 VpdReadDWord(); -extern int VpdSetupPara(); extern SK_VPD_STATUS *VpdStat(); extern int VpdKeys(); extern int VpdRead(); @@ -257,7 +243,6 @@ extern SK_BOOL VpdMayWrite(); extern int VpdWrite(); extern int VpdDelete(); extern int VpdUpdate(); -extern void VpdErrLog(); #endif /* SK_KR_PROTO */ #endif /* __INC_SKVPD_H_ */ diff --git a/drivers/net/sk98lin/skaddr.c b/drivers/net/sk98lin/skaddr.c index a7e25edc7fc..6e6c56aa6d6 100644 --- a/drivers/net/sk98lin/skaddr.c +++ b/drivers/net/sk98lin/skaddr.c @@ -87,6 +87,21 @@ static const SK_U16 OnesHash[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; static int Next0[SK_MAX_MACS] = {0}; #endif /* DEBUG */ +static int SkAddrGmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber, + SK_MAC_ADDR *pMc, int Flags); +static int SkAddrGmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber, + int Flags); +static int SkAddrGmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber); +static int SkAddrGmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC, + SK_U32 PortNumber, int NewPromMode); +static int SkAddrXmacMcAdd(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber, + SK_MAC_ADDR *pMc, int Flags); +static int SkAddrXmacMcClear(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber, + int Flags); +static int SkAddrXmacMcUpdate(SK_AC *pAC, SK_IOC IoC, SK_U32 PortNumber); +static int SkAddrXmacPromiscuousChange(SK_AC *pAC, SK_IOC IoC, + SK_U32 PortNumber, int NewPromMode); + /* functions ******************************************************************/ /****************************************************************************** @@ -372,7 +387,7 @@ int Flags) /* permanent/non-perm, sw-only */ * SK_ADDR_SUCCESS * SK_ADDR_ILLEGAL_PORT */ -int SkAddrXmacMcClear( +static int SkAddrXmacMcClear( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* Index of affected port */ @@ -429,7 +444,7 @@ int Flags) /* permanent/non-perm, sw-only */ * SK_ADDR_SUCCESS * SK_ADDR_ILLEGAL_PORT */ -int SkAddrGmacMcClear( +static int SkAddrGmacMcClear( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* Index of affected port */ @@ -519,7 +534,7 @@ int Flags) /* permanent/non-perm, sw-only */ * Returns: * Hash value of multicast address. */ -SK_U32 SkXmacMcHash( +static SK_U32 SkXmacMcHash( unsigned char *pMc) /* Multicast address */ { SK_U32 Idx; @@ -557,7 +572,7 @@ unsigned char *pMc) /* Multicast address */ * Returns: * Hash value of multicast address. */ -SK_U32 SkGmacMcHash( +static SK_U32 SkGmacMcHash( unsigned char *pMc) /* Multicast address */ { SK_U32 Data; @@ -672,7 +687,7 @@ int Flags) /* permanent/non-permanent */ * SK_MC_ILLEGAL_ADDRESS * SK_MC_RLMT_OVERFLOW */ -int SkAddrXmacMcAdd( +static int SkAddrXmacMcAdd( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* Port Number */ @@ -778,7 +793,7 @@ int Flags) /* permanent/non-permanent */ * SK_MC_FILTERING_INEXACT * SK_MC_ILLEGAL_ADDRESS */ -int SkAddrGmacMcAdd( +static int SkAddrGmacMcAdd( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* Port Number */ @@ -937,7 +952,7 @@ SK_U32 PortNumber) /* Port Number */ * SK_MC_FILTERING_INEXACT * SK_ADDR_ILLEGAL_PORT */ -int SkAddrXmacMcUpdate( +static int SkAddrXmacMcUpdate( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber) /* Port Number */ @@ -1082,7 +1097,7 @@ SK_U32 PortNumber) /* Port Number */ * SK_MC_FILTERING_INEXACT * SK_ADDR_ILLEGAL_PORT */ -int SkAddrGmacMcUpdate( +static int SkAddrGmacMcUpdate( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber) /* Port Number */ @@ -1468,7 +1483,7 @@ int NewPromMode) /* new promiscuous mode */ * SK_ADDR_SUCCESS * SK_ADDR_ILLEGAL_PORT */ -int SkAddrXmacPromiscuousChange( +static int SkAddrXmacPromiscuousChange( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* port whose promiscuous mode changes */ @@ -1585,7 +1600,7 @@ int NewPromMode) /* new promiscuous mode */ * SK_ADDR_SUCCESS * SK_ADDR_ILLEGAL_PORT */ -int SkAddrGmacPromiscuousChange( +static int SkAddrGmacPromiscuousChange( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* I/O context */ SK_U32 PortNumber, /* port whose promiscuous mode changes */ diff --git a/drivers/net/sk98lin/skgeinit.c b/drivers/net/sk98lin/skgeinit.c index 6cb49dd0225..67f1d6a5c15 100644 --- a/drivers/net/sk98lin/skgeinit.c +++ b/drivers/net/sk98lin/skgeinit.c @@ -57,34 +57,6 @@ static struct s_Config OemConfig = { #endif }; -/****************************************************************************** - * - * SkGePollRxD() - Enable / Disable Descriptor Polling of RxD Ring - * - * Description: - * Enable or disable the descriptor polling of the receive descriptor - * ring (RxD) for port 'Port'. - * The new configuration is *not* saved over any SkGeStopPort() and - * SkGeInitPort() calls. - * - * Returns: - * nothing - */ -void SkGePollRxD( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ -SK_BOOL PollRxD) /* SK_TRUE (enable pol.), SK_FALSE (disable pol.) */ -{ - SK_GEPORT *pPrt; - - pPrt = &pAC->GIni.GP[Port]; - - SK_OUT32(IoC, Q_ADDR(pPrt->PRxQOff, Q_CSR), (PollRxD) ? - CSR_ENA_POL : CSR_DIS_POL); -} /* SkGePollRxD */ - - /****************************************************************************** * * SkGePollTxD() - Enable / Disable Descriptor Polling of TxD Rings @@ -952,7 +924,7 @@ int Port) /* Port Index (MAC_1 + n) */ * Returns: * nothing */ -void SkGeInitRamIface( +static void SkGeInitRamIface( SK_AC *pAC, /* adapter context */ SK_IOC IoC) /* IO context */ { @@ -1409,83 +1381,6 @@ SK_IOC IoC) /* IO context */ } /* SkGeInit0*/ -#ifdef SK_PCI_RESET - -/****************************************************************************** - * - * SkGePciReset() - Reset PCI interface - * - * Description: - * o Read PCI configuration. - * o Change power state to 3. - * o Change power state to 0. - * o Restore PCI configuration. - * - * Returns: - * 0: Success. - * 1: Power state could not be changed to 3. - */ -static int SkGePciReset( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC) /* IO context */ -{ - int i; - SK_U16 PmCtlSts; - SK_U32 Bp1; - SK_U32 Bp2; - SK_U16 PciCmd; - SK_U8 Cls; - SK_U8 Lat; - SK_U8 ConfigSpace[PCI_CFG_SIZE]; - - /* - * Note: Switching to D3 state is like a software reset. - * Switching from D3 to D0 is a hardware reset. - * We have to save and restore the configuration space. - */ - for (i = 0; i < PCI_CFG_SIZE; i++) { - SkPciReadCfgDWord(pAC, i*4, &ConfigSpace[i]); - } - - /* We know the RAM Interface Arbiter is enabled. */ - SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D3); - SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts); - - if ((PmCtlSts & PCI_PM_STATE_MSK) != PCI_PM_STATE_D3) { - return(1); - } - - /* Return to D0 state. */ - SkPciWriteCfgWord(pAC, PCI_PM_CTL_STS, PCI_PM_STATE_D0); - - /* Check for D0 state. */ - SkPciReadCfgWord(pAC, PCI_PM_CTL_STS, &PmCtlSts); - - if ((PmCtlSts & PCI_PM_STATE_MSK) != PCI_PM_STATE_D0) { - return(1); - } - - /* Check PCI Config Registers. */ - SkPciReadCfgWord(pAC, PCI_COMMAND, &PciCmd); - SkPciReadCfgByte(pAC, PCI_CACHE_LSZ, &Cls); - SkPciReadCfgDWord(pAC, PCI_BASE_1ST, &Bp1); - SkPciReadCfgDWord(pAC, PCI_BASE_2ND, &Bp2); - SkPciReadCfgByte(pAC, PCI_LAT_TIM, &Lat); - - if (PciCmd != 0 || Cls != (SK_U8)0 || Lat != (SK_U8)0 || - (Bp1 & 0xfffffff0L) != 0 || Bp2 != 1) { - return(1); - } - - /* Restore PCI Config Space. */ - for (i = 0; i < PCI_CFG_SIZE; i++) { - SkPciWriteCfgDWord(pAC, i*4, ConfigSpace[i]); - } - - return(0); -} /* SkGePciReset */ - -#endif /* SK_PCI_RESET */ /****************************************************************************** * @@ -1524,10 +1419,6 @@ SK_IOC IoC) /* IO context */ /* save CLK_RUN bits (YUKON-Lite) */ SK_IN16(IoC, B0_CTST, &CtrlStat); -#ifdef SK_PCI_RESET - (void)SkGePciReset(pAC, IoC); -#endif /* SK_PCI_RESET */ - /* do the SW-reset */ SK_OUT8(IoC, B0_CTST, CS_RST_SET); @@ -1991,11 +1882,6 @@ SK_IOC IoC) /* IO context */ int i; SK_U16 Word; -#ifdef SK_PHY_LP_MODE - SK_U8 Byte; - SK_U16 PmCtlSts; -#endif /* SK_PHY_LP_MODE */ - #if (!defined(SK_SLIM) && !defined(VCPU)) /* ensure I2C is ready */ SkI2cWaitIrq(pAC, IoC); @@ -2010,38 +1896,6 @@ SK_IOC IoC) /* IO context */ } } -#ifdef SK_PHY_LP_MODE - /* - * for power saving purposes within mobile environments - * we set the PHY to coma mode and switch to D3 power state. - */ - if (pAC->GIni.GIYukonLite && - pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) { - - /* for all ports switch PHY to coma mode */ - for (i = 0; i < pAC->GIni.GIMacsFound; i++) { - - SkGmEnterLowPowerMode(pAC, IoC, i, PHY_PM_DEEP_SLEEP); - } - - if (pAC->GIni.GIVauxAvail) { - /* switch power to VAUX */ - Byte = PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF; - - SK_OUT8(IoC, B0_POWER_CTRL, Byte); - } - - /* switch to D3 state */ - SK_IN16(IoC, PCI_C(PCI_PM_CTL_STS), &PmCtlSts); - - PmCtlSts |= PCI_PM_STATE_D3; - - SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); - - SK_OUT16(IoC, PCI_C(PCI_PM_CTL_STS), PmCtlSts); - } -#endif /* SK_PHY_LP_MODE */ - /* Reset all bits in the PCI STATUS register */ /* * Note: PCI Cfg cycles cannot be used, because they are not diff --git a/drivers/net/sk98lin/skgemib.c b/drivers/net/sk98lin/skgemib.c index 2991bc85cf2..0a6f67a7a39 100644 --- a/drivers/net/sk98lin/skgemib.c +++ b/drivers/net/sk98lin/skgemib.c @@ -871,13 +871,6 @@ PNMI_STATIC const SK_PNMI_TAB_ENTRY IdTable[] = { sizeof(SK_PNMI_CONF), SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyType), SK_PNMI_RO, MacPrivateConf, 0}, -#ifdef SK_PHY_LP_MODE - {OID_SKGE_PHY_LP_MODE, - SK_PNMI_MAC_ENTRIES, - sizeof(SK_PNMI_CONF), - SK_PNMI_OFF(Conf) + SK_PNMI_CNF_OFF(ConfPhyMode), - SK_PNMI_RW, MacPrivateConf, 0}, -#endif {OID_SKGE_LINK_CAP, SK_PNMI_MAC_ENTRIES, sizeof(SK_PNMI_CONF), diff --git a/drivers/net/sk98lin/skgepnmi.c b/drivers/net/sk98lin/skgepnmi.c index a386172107e..b36dd9ac6b2 100644 --- a/drivers/net/sk98lin/skgepnmi.c +++ b/drivers/net/sk98lin/skgepnmi.c @@ -56,10 +56,6 @@ static const char SysKonnectFileId[] = * Public Function prototypes */ int SkPnmiInit(SK_AC *pAC, SK_IOC IoC, int level); -int SkPnmiGetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf, - unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); -int SkPnmiPreSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf, - unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); int SkPnmiSetVar(SK_AC *pAC, SK_IOC IoC, SK_U32 Id, void *pBuf, unsigned int *pLen, SK_U32 Instance, SK_U32 NetIndex); int SkPnmiGetStruct(SK_AC *pAC, SK_IOC IoC, void *pBuf, @@ -587,7 +583,7 @@ int Level) /* Initialization level */ * exist (e.g. port instance 3 on a two port * adapter. */ -int SkPnmiGetVar( +static int SkPnmiGetVar( SK_AC *pAC, /* Pointer to adapter context */ SK_IOC IoC, /* IO context handle */ SK_U32 Id, /* Object ID that is to be processed */ @@ -629,7 +625,7 @@ SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ * exist (e.g. port instance 3 on a two port * adapter. */ -int SkPnmiPreSetVar( +static int SkPnmiPreSetVar( SK_AC *pAC, /* Pointer to adapter context */ SK_IOC IoC, /* IO context handle */ SK_U32 Id, /* Object ID that is to be processed */ @@ -5062,9 +5058,6 @@ SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ case OID_SKGE_SPEED_CAP: case OID_SKGE_SPEED_MODE: case OID_SKGE_SPEED_STATUS: -#ifdef SK_PHY_LP_MODE - case OID_SKGE_PHY_LP_MODE: -#endif if (*pLen < (Limit - LogPortIndex) * sizeof(SK_U8)) { *pLen = (Limit - LogPortIndex) * sizeof(SK_U8); @@ -5140,28 +5133,6 @@ SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ Offset += sizeof(SK_U32); break; -#ifdef SK_PHY_LP_MODE - case OID_SKGE_PHY_LP_MODE: - if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ - if (LogPortIndex == 0) { - continue; - } - else { - /* Get value for physical ports */ - PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex); - Val8 = (SK_U8) pAC->GIni.GP[PhysPortIndex].PPhyPowerState; - *pBufPtr = Val8; - } - } - else { /* DualNetMode */ - - Val8 = (SK_U8) pAC->GIni.GP[PhysPortIndex].PPhyPowerState; - *pBufPtr = Val8; - } - Offset += sizeof(SK_U8); - break; -#endif - case OID_SKGE_LINK_CAP: if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ if (LogPortIndex == 0) { @@ -5478,16 +5449,6 @@ SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ } break; -#ifdef SK_PHY_LP_MODE - case OID_SKGE_PHY_LP_MODE: - if (*pLen < Limit - LogPortIndex) { - - *pLen = Limit - LogPortIndex; - return (SK_PNMI_ERR_TOO_SHORT); - } - break; -#endif - case OID_SKGE_MTU: if (*pLen < sizeof(SK_U32)) { @@ -5845,116 +5806,6 @@ SK_U32 NetIndex) /* NetIndex (0..n), in single net mode always zero */ Offset += sizeof(SK_U32); break; -#ifdef SK_PHY_LP_MODE - case OID_SKGE_PHY_LP_MODE: - /* The preset ends here */ - if (Action == SK_PNMI_PRESET) { - - return (SK_PNMI_ERR_OK); - } - - if (!pAC->Pnmi.DualNetActiveFlag) { /* SingleNetMode */ - if (LogPortIndex == 0) { - Offset = 0; - continue; - } - else { - /* Set value for physical ports */ - PhysPortIndex = SK_PNMI_PORT_LOG2PHYS(pAC, LogPortIndex); - - switch (*(pBuf + Offset)) { - case 0: - /* If LowPowerMode is active, we can leave it. */ - if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState) { - - Val32 = SkGmLeaveLowPowerMode(pAC, IoC, PhysPortIndex); - - if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState < 3) { - - SkDrvInitAdapter(pAC); - } - break; - } - else { - *pLen = 0; - return (SK_PNMI_ERR_GENERAL); - } - case 1: - case 2: - case 3: - case 4: - /* If no LowPowerMode is active, we can enter it. */ - if (!pAC->GIni.GP[PhysPortIndex].PPhyPowerState) { - - if ((*(pBuf + Offset)) < 3) { - - SkDrvDeInitAdapter(pAC); - } - - Val32 = SkGmEnterLowPowerMode(pAC, IoC, PhysPortIndex, *pBuf); - break; - } - else { - *pLen = 0; - return (SK_PNMI_ERR_GENERAL); - } - default: - *pLen = 0; - return (SK_PNMI_ERR_BAD_VALUE); - } - } - } - else { /* DualNetMode */ - - switch (*(pBuf + Offset)) { - case 0: - /* If we are in a LowPowerMode, we can leave it. */ - if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState) { - - Val32 = SkGmLeaveLowPowerMode(pAC, IoC, PhysPortIndex); - - if (pAC->GIni.GP[PhysPortIndex].PPhyPowerState < 3) { - - SkDrvInitAdapter(pAC); - } - break; - } - else { - *pLen = 0; - return (SK_PNMI_ERR_GENERAL); - } - - case 1: - case 2: - case 3: - case 4: - /* If we are not already in LowPowerMode, we can enter it. */ - if (!pAC->GIni.GP[PhysPortIndex].PPhyPowerState) { - - if ((*(pBuf + Offset)) < 3) { - - SkDrvDeInitAdapter(pAC); - } - else { - - Val32 = SkGmEnterLowPowerMode(pAC, IoC, PhysPortIndex, *pBuf); - } - break; - } - else { - *pLen = 0; - return (SK_PNMI_ERR_GENERAL); - } - - default: - *pLen = 0; - return (SK_PNMI_ERR_BAD_VALUE); - } - } - Offset += sizeof(SK_U8); - break; -#endif - default: SK_DBG_MSG(pAC, SK_DBGMOD_PNMI, SK_DBGCAT_ERR, ("MacPrivateConf: Unknown OID should be handled before set")); diff --git a/drivers/net/sk98lin/skgesirq.c b/drivers/net/sk98lin/skgesirq.c index 87520f0057d..ab66d80a445 100644 --- a/drivers/net/sk98lin/skgesirq.c +++ b/drivers/net/sk98lin/skgesirq.c @@ -265,7 +265,7 @@ int Port) /* Port Index (MAC_1 + n) */ * * Returns: N/A */ -void SkHWLinkUp( +static void SkHWLinkUp( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ int Port) /* Port Index (MAC_1 + n) */ @@ -612,14 +612,6 @@ SK_U32 Istatus) /* Interrupt status word */ * we ignore those */ pPrt->HalfDupTimerActive = SK_TRUE; -#ifdef XXX - Len = sizeof(SK_U64); - SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets, - &Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, 0), - pAC->Rlmt.Port[0].Net->NetNumber); - - pPrt->LastOctets = Octets; -#endif /* XXX */ /* Snap statistic counters */ (void)SkXmUpdateStats(pAC, IoC, 0); @@ -653,14 +645,6 @@ SK_U32 Istatus) /* Interrupt status word */ pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) && !pPrt->HalfDupTimerActive) { pPrt->HalfDupTimerActive = SK_TRUE; -#ifdef XXX - Len = sizeof(SK_U64); - SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets, - &Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, 1), - pAC->Rlmt.Port[1].Net->NetNumber); - - pPrt->LastOctets = Octets; -#endif /* XXX */ /* Snap statistic counters */ (void)SkXmUpdateStats(pAC, IoC, 1); @@ -2085,12 +2069,6 @@ SK_EVPARA Para) /* Event specific Parameter */ pPrt->HalfDupTimerActive = SK_FALSE; if (pPrt->PLinkModeStatus == SK_LMODE_STAT_HALF || pPrt->PLinkModeStatus == SK_LMODE_STAT_AUTOHALF) { -#ifdef XXX - Len = sizeof(SK_U64); - SkPnmiGetVar(pAC, IoC, OID_SKGE_STAT_TX_OCTETS, (char *)&Octets, - &Len, (SK_U32)SK_PNMI_PORT_PHYS2INST(pAC, Port), - pAC->Rlmt.Port[Port].Net->NetNumber); -#endif /* XXX */ /* Snap statistic counters */ (void)SkXmUpdateStats(pAC, IoC, Port); diff --git a/drivers/net/sk98lin/ski2c.c b/drivers/net/sk98lin/ski2c.c index 075a0464e56..79bf57cb532 100644 --- a/drivers/net/sk98lin/ski2c.c +++ b/drivers/net/sk98lin/ski2c.c @@ -396,7 +396,7 @@ int Rw) /* Read / Write Flag */ * 1: error, transfer does not complete, I2C transfer * killed, wait loop terminated. */ -int SkI2cWait( +static int SkI2cWait( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ int Event) /* complete event to wait for (I2C_READ or I2C_WRITE) */ @@ -481,7 +481,7 @@ SK_IOC IoC) /* I/O Context */ * returns 0: success * 1: error */ -int SkI2cWrite( +static int SkI2cWrite( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_U32 I2cData, /* I2C Data to write */ @@ -538,7 +538,7 @@ int I2cBurst) /* I2C Burst Flag */ * 1 if the read is completed * 0 if the read must be continued (I2C Bus still allocated) */ -int SkI2cReadSensor( +static int SkI2cReadSensor( SK_AC *pAC, /* Adapter Context */ SK_IOC IoC, /* I/O Context */ SK_SENSOR *pSen) /* Sensor to be read */ diff --git a/drivers/net/sk98lin/sklm80.c b/drivers/net/sk98lin/sklm80.c index 68292d18175..a204f5bb55d 100644 --- a/drivers/net/sk98lin/sklm80.c +++ b/drivers/net/sk98lin/sklm80.c @@ -34,79 +34,7 @@ static const char SysKonnectFileId[] = #include "h/lm80.h" #include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */ -#ifdef SK_DIAG -#define BREAK_OR_WAIT(pAC,IoC,Event) SkI2cWait(pAC,IoC,Event) -#else /* nSK_DIAG */ #define BREAK_OR_WAIT(pAC,IoC,Event) break -#endif /* nSK_DIAG */ - -#ifdef SK_DIAG -/* - * read the register 'Reg' from the device 'Dev' - * - * return read error -1 - * success the read value - */ -int SkLm80RcvReg( -SK_IOC IoC, /* Adapter Context */ -int Dev, /* I2C device address */ -int Reg) /* register to read */ -{ - int Val = 0; - int TempExt; - - /* Signal device number */ - if (SkI2cSndDev(IoC, Dev, I2C_WRITE)) { - return(-1); - } - - if (SkI2cSndByte(IoC, Reg)) { - return(-1); - } - - /* repeat start */ - if (SkI2cSndDev(IoC, Dev, I2C_READ)) { - return(-1); - } - - switch (Reg) { - case LM80_TEMP_IN: - Val = (int)SkI2cRcvByte(IoC, 1); - - /* First: correct the value: it might be negative */ - if ((Val & 0x80) != 0) { - /* Value is negative */ - Val = Val - 256; - } - Val = Val * SK_LM80_TEMP_LSB; - SkI2cStop(IoC); - - TempExt = (int)SkLm80RcvReg(IoC, LM80_ADDR, LM80_TEMP_CTRL); - - if (Val > 0) { - Val += ((TempExt >> 7) * SK_LM80_TEMPEXT_LSB); - } - else { - Val -= ((TempExt >> 7) * SK_LM80_TEMPEXT_LSB); - } - return(Val); - break; - case LM80_VT0_IN: - case LM80_VT1_IN: - case LM80_VT2_IN: - case LM80_VT3_IN: - Val = (int)SkI2cRcvByte(IoC, 1) * SK_LM80_VT_LSB; - break; - - default: - Val = (int)SkI2cRcvByte(IoC, 1); - break; - } - - SkI2cStop(IoC); - return(Val); -} -#endif /* SK_DIAG */ /* * read a sensors value (LM80 specific) diff --git a/drivers/net/sk98lin/skrlmt.c b/drivers/net/sk98lin/skrlmt.c index 9ea11ab2296..be8d1ccddf6 100644 --- a/drivers/net/sk98lin/skrlmt.c +++ b/drivers/net/sk98lin/skrlmt.c @@ -282,7 +282,6 @@ typedef struct s_SpTreeRlmtPacket { SK_MAC_ADDR SkRlmtMcAddr = {{0x01, 0x00, 0x5A, 0x52, 0x4C, 0x4D}}; SK_MAC_ADDR BridgeMcAddr = {{0x01, 0x80, 0xC2, 0x00, 0x00, 0x00}}; -SK_MAC_ADDR BcAddr = {{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}}; /* local variables ************************************************************/ diff --git a/drivers/net/sk98lin/skvpd.c b/drivers/net/sk98lin/skvpd.c index eb3c8988ced..17786056c66 100644 --- a/drivers/net/sk98lin/skvpd.c +++ b/drivers/net/sk98lin/skvpd.c @@ -132,65 +132,6 @@ int addr) /* VPD address */ #endif /* SKDIAG */ -#if 0 - -/* - Write the dword 'data' at address 'addr' into the VPD EEPROM, and - verify that the data is written. - - Needed Time: - -. MIN MAX -. ------------------------------------------------------------------- -. write 1.8 ms 3.6 ms -. internal write cyles 0.7 ms 7.0 ms -. ------------------------------------------------------------------- -. over all program time 2.5 ms 10.6 ms -. read 1.3 ms 2.6 ms -. ------------------------------------------------------------------- -. over all 3.8 ms 13.2 ms -. - - - Returns 0: success - 1: error, I2C transfer does not terminate - 2: error, data verify error - - */ -static int VpdWriteDWord( -SK_AC *pAC, /* pAC pointer */ -SK_IOC IoC, /* IO Context */ -int addr, /* VPD address */ -SK_U32 data) /* VPD data to write */ -{ - /* start VPD write */ - /* Don't swap here, it's a data stream of bytes */ - SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_CTRL, - ("VPD write dword at addr 0x%x, data = 0x%x\n",addr,data)); - VPD_OUT32(pAC, IoC, PCI_VPD_DAT_REG, (SK_U32)data); - /* But do it here */ - addr |= VPD_WRITE; - - VPD_OUT16(pAC, IoC, PCI_VPD_ADR_REG, (SK_U16)(addr | VPD_WRITE)); - - /* this may take up to 10,6 ms */ - if (VpdWait(pAC, IoC, VPD_WRITE)) { - SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, - ("Write Timed Out\n")); - return(1); - }; - - /* verify data */ - if (VpdReadDWord(pAC, IoC, addr) != data) { - SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR | SK_DBGCAT_FATAL, - ("Data Verify Error\n")); - return(2); - } - return(0); -} /* VpdWriteDWord */ - -#endif /* 0 */ - /* * Read one Stream of 'len' bytes of VPD data, starting at 'addr' from * or to the I2C EEPROM. @@ -728,7 +669,7 @@ char *etp) /* end pointer input position */ * 6: fatal VPD error * */ -int VpdSetupPara( +static int VpdSetupPara( SK_AC *pAC, /* common data base */ const char *key, /* keyword to insert */ const char *buf, /* buffer with the keyword value */ @@ -1148,50 +1089,3 @@ SK_IOC IoC) /* IO Context */ return(0); } - - -/* - * Read the contents of the VPD EEPROM and copy it to the VPD buffer - * if not already done. If the keyword "VF" is not present it will be - * created and the error log message will be stored to this keyword. - * If "VF" is not present the error log message will be stored to the - * keyword "VL". "VL" will created or overwritten if "VF" is present. - * The VPD read/write area is saved to the VPD EEPROM. - * - * returns nothing, errors will be ignored. - */ -void VpdErrLog( -SK_AC *pAC, /* common data base */ -SK_IOC IoC, /* IO Context */ -char *msg) /* error log message */ -{ - SK_VPD_PARA *v, vf; /* VF */ - int len; - - SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, - ("VPD error log msg %s\n", msg)); - if ((pAC->vpd.v.vpd_status & VPD_VALID) == 0) { - if (VpdInit(pAC, IoC) != 0) { - SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_ERR, - ("VPD init error\n")); - return; - } - } - - len = strlen(msg); - if (len > VPD_MAX_LEN) { - /* cut it */ - len = VPD_MAX_LEN; - } - if ((v = vpd_find_para(pAC, VPD_VF, &vf)) != NULL) { - SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("overwrite VL\n")); - (void)VpdSetupPara(pAC, VPD_VL, msg, len, VPD_RW_KEY, OWR_KEY); - } - else { - SK_DBG_MSG(pAC, SK_DBGMOD_VPD, SK_DBGCAT_TX, ("write VF\n")); - (void)VpdSetupPara(pAC, VPD_VF, msg, len, VPD_RW_KEY, ADD_KEY); - } - - (void)VpdUpdate(pAC, IoC); -} - diff --git a/drivers/net/sk98lin/skxmac2.c b/drivers/net/sk98lin/skxmac2.c index 42d2d963150..b4e75022a65 100644 --- a/drivers/net/sk98lin/skxmac2.c +++ b/drivers/net/sk98lin/skxmac2.c @@ -41,13 +41,13 @@ static const char SysKonnectFileId[] = #endif #ifdef GENESIS -BCOM_HACK BcomRegA1Hack[] = { +static BCOM_HACK BcomRegA1Hack[] = { { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1104 }, { 0x17, 0x0013 }, { 0x15, 0x0404 }, { 0x17, 0x8006 }, { 0x15, 0x0132 }, { 0x17, 0x8006 }, { 0x15, 0x0232 }, { 0x17, 0x800D }, { 0x15, 0x000F }, { 0x18, 0x0420 }, { 0, 0 } }; -BCOM_HACK BcomRegC0Hack[] = { +static BCOM_HACK BcomRegC0Hack[] = { { 0x18, 0x0c20 }, { 0x17, 0x0012 }, { 0x15, 0x1204 }, { 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 }, { 0, 0 } @@ -790,7 +790,7 @@ int Port) /* Port Index (MAC_1 + n) */ * Returns: * nothing */ -void SkMacFlushRxFifo( +static void SkMacFlushRxFifo( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ int Port) /* Port Index (MAC_1 + n) */ @@ -1231,38 +1231,6 @@ int Port) /* Port Index (MAC_1 + n) */ } /* SkMacHardRst */ -/****************************************************************************** - * - * SkMacClearRst() - Clear the MAC reset - * - * Description: calls a clear MAC reset routine dep. on board type - * - * Returns: - * nothing - */ -void SkMacClearRst( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* IO context */ -int Port) /* Port Index (MAC_1 + n) */ -{ - -#ifdef GENESIS - if (pAC->GIni.GIGenesis) { - - SkXmClearRst(pAC, IoC, Port); - } -#endif /* GENESIS */ - -#ifdef YUKON - if (pAC->GIni.GIYukon) { - - SkGmClearRst(pAC, IoC, Port); - } -#endif /* YUKON */ - -} /* SkMacClearRst */ - - #ifdef GENESIS /****************************************************************************** * @@ -1713,7 +1681,7 @@ int Port) /* Port Index (MAC_1 + n) */ * Returns: * nothing */ -void SkXmInitDupMd( +static void SkXmInitDupMd( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ int Port) /* Port Index (MAC_1 + n) */ @@ -1761,7 +1729,7 @@ int Port) /* Port Index (MAC_1 + n) */ * Returns: * nothing */ -void SkXmInitPauseMd( +static void SkXmInitPauseMd( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ int Port) /* Port Index (MAC_1 + n) */ @@ -2076,283 +2044,7 @@ SK_BOOL DoLoop) /* Should a Phy LoopBack be set-up? */ } /* SkXmInitPhyBcom */ #endif /* GENESIS */ - #ifdef YUKON -#ifndef SK_SLIM -/****************************************************************************** - * - * SkGmEnterLowPowerMode() - * - * Description: - * This function sets the Marvell Alaska PHY to the low power mode - * given by parameter mode. - * The following low power modes are available: - * - * - Coma Mode (Deep Sleep): - * Power consumption: ~15 - 30 mW - * The PHY cannot wake up on its own. - * - * - IEEE 22.2.4.1.5 compatible power down mode - * Power consumption: ~240 mW - * The PHY cannot wake up on its own. - * - * - energy detect mode - * Power consumption: ~160 mW - * The PHY can wake up on its own by detecting activity - * on the CAT 5 cable. - * - * - energy detect plus mode - * Power consumption: ~150 mW - * The PHY can wake up on its own by detecting activity - * on the CAT 5 cable. - * Connected devices can be woken up by sending normal link - * pulses every one second. - * - * Note: - * - * Returns: - * 0: ok - * 1: error - */ -int SkGmEnterLowPowerMode( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* IO context */ -int Port, /* Port Index (e.g. MAC_1) */ -SK_U8 Mode) /* low power mode */ -{ - SK_U16 Word; - SK_U32 DWord; - SK_U8 LastMode; - int Ret = 0; - - if (pAC->GIni.GIYukonLite && - pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) { - - /* save current power mode */ - LastMode = pAC->GIni.GP[Port].PPhyPowerState; - pAC->GIni.GP[Port].PPhyPowerState = Mode; - - switch (Mode) { - /* coma mode (deep sleep) */ - case PHY_PM_DEEP_SLEEP: - /* setup General Purpose Control Register */ - GM_OUT16(IoC, 0, GM_GP_CTRL, GM_GPCR_FL_PASS | - GM_GPCR_SPEED_100 | GM_GPCR_AU_ALL_DIS); - - /* apply COMA mode workaround */ - SkGmPhyWrite(pAC, IoC, Port, 29, 0x001f); - SkGmPhyWrite(pAC, IoC, Port, 30, 0xfff3); - - SK_IN32(IoC, PCI_C(PCI_OUR_REG_1), &DWord); - - SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); - - /* Set PHY to Coma Mode */ - SK_OUT32(IoC, PCI_C(PCI_OUR_REG_1), DWord | PCI_PHY_COMA); - - SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF); - - break; - - /* IEEE 22.2.4.1.5 compatible power down mode */ - case PHY_PM_IEEE_POWER_DOWN: - /* - * - disable MAC 125 MHz clock - * - allow MAC power down - */ - SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); - Word |= PHY_M_PC_DIS_125CLK; - Word &= ~PHY_M_PC_MAC_POW_UP; - SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); - - /* - * register changes must be followed by a software - * reset to take effect - */ - SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); - Word |= PHY_CT_RESET; - SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); - - /* switch IEEE compatible power down mode on */ - SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); - Word |= PHY_CT_PDOWN; - SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); - break; - - /* energy detect and energy detect plus mode */ - case PHY_PM_ENERGY_DETECT: - case PHY_PM_ENERGY_DETECT_PLUS: - /* - * - disable MAC 125 MHz clock - */ - SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); - Word |= PHY_M_PC_DIS_125CLK; - SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); - - /* activate energy detect mode 1 */ - SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); - - /* energy detect mode */ - if (Mode == PHY_PM_ENERGY_DETECT) { - Word |= PHY_M_PC_EN_DET; - } - /* energy detect plus mode */ - else { - Word |= PHY_M_PC_EN_DET_PLUS; - } - - SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); - - /* - * reinitialize the PHY to force a software reset - * which is necessary after the register settings - * for the energy detect modes. - * Furthermore reinitialisation prevents that the - * PHY is running out of a stable state. - */ - SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE); - break; - - /* don't change current power mode */ - default: - pAC->GIni.GP[Port].PPhyPowerState = LastMode; - Ret = 1; - break; - } - } - /* low power modes are not supported by this chip */ - else { - Ret = 1; - } - - return(Ret); - -} /* SkGmEnterLowPowerMode */ - -/****************************************************************************** - * - * SkGmLeaveLowPowerMode() - * - * Description: - * Leave the current low power mode and switch to normal mode - * - * Note: - * - * Returns: - * 0: ok - * 1: error - */ -int SkGmLeaveLowPowerMode( -SK_AC *pAC, /* adapter context */ -SK_IOC IoC, /* IO context */ -int Port) /* Port Index (e.g. MAC_1) */ -{ - SK_U32 DWord; - SK_U16 Word; - SK_U8 LastMode; - int Ret = 0; - - if (pAC->GIni.GIYukonLite && - pAC->GIni.GIChipRev >= CHIP_REV_YU_LITE_A3) { - - /* save current power mode */ - LastMode = pAC->GIni.GP[Port].PPhyPowerState; - pAC->GIni.GP[Port].PPhyPowerState = PHY_PM_OPERATIONAL_MODE; - - switch (LastMode) { - /* coma mode (deep sleep) */ - case PHY_PM_DEEP_SLEEP: - SK_IN32(IoC, PCI_C(PCI_OUR_REG_1), &DWord); - - SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_ON); - - /* Release PHY from Coma Mode */ - SK_OUT32(IoC, PCI_C(PCI_OUR_REG_1), DWord & ~PCI_PHY_COMA); - - SK_OUT8(IoC, B2_TST_CTRL1, TST_CFG_WRITE_OFF); - - SK_IN32(IoC, B2_GP_IO, &DWord); - - /* set to output */ - DWord |= (GP_DIR_9 | GP_IO_9); - - /* set PHY reset */ - SK_OUT32(IoC, B2_GP_IO, DWord); - - DWord &= ~GP_IO_9; /* clear PHY reset (active high) */ - - /* clear PHY reset */ - SK_OUT32(IoC, B2_GP_IO, DWord); - break; - - /* IEEE 22.2.4.1.5 compatible power down mode */ - case PHY_PM_IEEE_POWER_DOWN: - /* - * - enable MAC 125 MHz clock - * - set MAC power up - */ - SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); - Word &= ~PHY_M_PC_DIS_125CLK; - Word |= PHY_M_PC_MAC_POW_UP; - SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); - - /* - * register changes must be followed by a software - * reset to take effect - */ - SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); - Word |= PHY_CT_RESET; - SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); - - /* switch IEEE compatible power down mode off */ - SkGmPhyRead(pAC, IoC, Port, PHY_MARV_CTRL, &Word); - Word &= ~PHY_CT_PDOWN; - SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_CTRL, Word); - break; - - /* energy detect and energy detect plus mode */ - case PHY_PM_ENERGY_DETECT: - case PHY_PM_ENERGY_DETECT_PLUS: - /* - * - enable MAC 125 MHz clock - */ - SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); - Word &= ~PHY_M_PC_DIS_125CLK; - SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); - - /* disable energy detect mode */ - SkGmPhyRead(pAC, IoC, Port, PHY_MARV_PHY_CTRL, &Word); - Word &= ~PHY_M_PC_EN_DET_MSK; - SkGmPhyWrite(pAC, IoC, Port, PHY_MARV_PHY_CTRL, Word); - - /* - * reinitialize the PHY to force a software reset - * which is necessary after the register settings - * for the energy detect modes. - * Furthermore reinitialisation prevents that the - * PHY is running out of a stable state. - */ - SkGmInitPhyMarv(pAC, IoC, Port, SK_FALSE); - break; - - /* don't change current power mode */ - default: - pAC->GIni.GP[Port].PPhyPowerState = LastMode; - Ret = 1; - break; - } - } - /* low power modes are not supported by this chip */ - else { - Ret = 1; - } - - return(Ret); - -} /* SkGmLeaveLowPowerMode */ -#endif /* !SK_SLIM */ - - /****************************************************************************** * * SkGmInitPhyMarv() - Initialize the Marvell Phy registers @@ -3420,145 +3112,6 @@ int Port) /* Port Index (MAC_1 + n) */ } /* SkMacAutoNegDone */ -#ifdef GENESIS -/****************************************************************************** - * - * SkXmSetRxTxEn() - Special Set Rx/Tx Enable and some features in XMAC - * - * Description: - * sets MAC or PHY LoopBack and Duplex Mode in the MMU Command Reg. - * enables Rx/Tx - * - * Returns: N/A - */ -static void SkXmSetRxTxEn( -SK_AC *pAC, /* Adapter Context */ -SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ -int Para) /* Parameter to set: MAC or PHY LoopBack, Duplex Mode */ -{ - SK_U16 Word; - - XM_IN16(IoC, Port, XM_MMU_CMD, &Word); - - switch (Para & (SK_MAC_LOOPB_ON | SK_MAC_LOOPB_OFF)) { - case SK_MAC_LOOPB_ON: - Word |= XM_MMU_MAC_LB; - break; - case SK_MAC_LOOPB_OFF: - Word &= ~XM_MMU_MAC_LB; - break; - } - - switch (Para & (SK_PHY_LOOPB_ON | SK_PHY_LOOPB_OFF)) { - case SK_PHY_LOOPB_ON: - Word |= XM_MMU_GMII_LOOP; - break; - case SK_PHY_LOOPB_OFF: - Word &= ~XM_MMU_GMII_LOOP; - break; - } - - switch (Para & (SK_PHY_FULLD_ON | SK_PHY_FULLD_OFF)) { - case SK_PHY_FULLD_ON: - Word |= XM_MMU_GMII_FD; - break; - case SK_PHY_FULLD_OFF: - Word &= ~XM_MMU_GMII_FD; - break; - } - - XM_OUT16(IoC, Port, XM_MMU_CMD, Word | XM_MMU_ENA_RX | XM_MMU_ENA_TX); - - /* dummy read to ensure writing */ - XM_IN16(IoC, Port, XM_MMU_CMD, &Word); - -} /* SkXmSetRxTxEn */ -#endif /* GENESIS */ - - -#ifdef YUKON -/****************************************************************************** - * - * SkGmSetRxTxEn() - Special Set Rx/Tx Enable and some features in GMAC - * - * Description: - * sets MAC LoopBack and Duplex Mode in the General Purpose Control Reg. - * enables Rx/Tx - * - * Returns: N/A - */ -static void SkGmSetRxTxEn( -SK_AC *pAC, /* Adapter Context */ -SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ -int Para) /* Parameter to set: MAC LoopBack, Duplex Mode */ -{ - SK_U16 Ctrl; - - GM_IN16(IoC, Port, GM_GP_CTRL, &Ctrl); - - switch (Para & (SK_MAC_LOOPB_ON | SK_MAC_LOOPB_OFF)) { - case SK_MAC_LOOPB_ON: - Ctrl |= GM_GPCR_LOOP_ENA; - break; - case SK_MAC_LOOPB_OFF: - Ctrl &= ~GM_GPCR_LOOP_ENA; - break; - } - - switch (Para & (SK_PHY_FULLD_ON | SK_PHY_FULLD_OFF)) { - case SK_PHY_FULLD_ON: - Ctrl |= GM_GPCR_DUP_FULL; - break; - case SK_PHY_FULLD_OFF: - Ctrl &= ~GM_GPCR_DUP_FULL; - break; - } - - GM_OUT16(IoC, Port, GM_GP_CTRL, (SK_U16)(Ctrl | GM_GPCR_RX_ENA | - GM_GPCR_TX_ENA)); - - /* dummy read to ensure writing */ - GM_IN16(IoC, Port, GM_GP_CTRL, &Ctrl); - -} /* SkGmSetRxTxEn */ -#endif /* YUKON */ - - -#ifndef SK_SLIM -/****************************************************************************** - * - * SkMacSetRxTxEn() - Special Set Rx/Tx Enable and parameters - * - * Description: calls the Special Set Rx/Tx Enable routines dep. on board type - * - * Returns: N/A - */ -void SkMacSetRxTxEn( -SK_AC *pAC, /* Adapter Context */ -SK_IOC IoC, /* IO context */ -int Port, /* Port Index (MAC_1 + n) */ -int Para) -{ -#ifdef GENESIS - if (pAC->GIni.GIGenesis) { - - SkXmSetRxTxEn(pAC, IoC, Port, Para); - } -#endif /* GENESIS */ - -#ifdef YUKON - if (pAC->GIni.GIYukon) { - - SkGmSetRxTxEn(pAC, IoC, Port, Para); - } -#endif /* YUKON */ - -} /* SkMacSetRxTxEn */ -#endif /* !SK_SLIM */ - - /****************************************************************************** * * SkMacRxTxEnable() - Enable Rx/Tx activity if port is up @@ -3976,7 +3529,7 @@ SK_U16 PhyStat) /* PHY Status word to analyse */ * Returns: * nothing */ -void SkXmIrq( +static void SkXmIrq( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ int Port) /* Port Index (MAC_1 + n) */ @@ -4112,7 +3665,7 @@ int Port) /* Port Index (MAC_1 + n) */ * Returns: * nothing */ -void SkGmIrq( +static void SkGmIrq( SK_AC *pAC, /* adapter context */ SK_IOC IoC, /* IO context */ int Port) /* Port Index (MAC_1 + n) */ -- cgit v1.2.3 From ff5688ae1cedfb175b5ed0f319d03ad2e5ee005d Mon Sep 17 00:00:00 2001 From: Marcelo Feitoza Parisi Date: Mon, 9 Jan 2006 18:37:15 -0800 Subject: [PATCH] drivers/net/*: use time_after() and friends They deal with wrapping correctly and are nicer to read. Also make jiffies-holding variables unsigned long. Signed-off-by: Marcelo Feitoza Parisi Signed-off-by: Alexey Dobriyan Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/3c523.c | 9 +++++---- drivers/net/3c59x.c | 3 ++- drivers/net/apne.c | 7 ++++--- drivers/net/arcnet/arcnet.c | 3 ++- drivers/net/arm/etherh.c | 3 ++- drivers/net/eth16i.c | 11 ++++++----- drivers/net/hamradio/baycom_epp.c | 2 +- drivers/net/hp100.c | 5 +++-- drivers/net/ne-h8300.c | 5 +++-- drivers/net/ne.c | 7 ++++--- drivers/net/ne2.c | 7 ++++--- drivers/net/ns83820.c | 5 +++-- drivers/net/oaknet.c | 3 ++- drivers/net/pcmcia/3c589_cs.c | 3 ++- drivers/net/ppp_async.c | 3 ++- drivers/net/seeq8005.c | 5 +++-- drivers/net/shaper.c | 3 ++- drivers/net/tokenring/lanstreamer.c | 3 ++- drivers/net/tokenring/olympic.c | 9 +++++---- drivers/net/tulip/pnic.c | 3 ++- drivers/net/wireless/strip.c | 4 ++-- drivers/net/zorro8390.c | 7 ++++--- 22 files changed, 65 insertions(+), 45 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index 9e1fe2e0478..b40885d4168 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -105,6 +105,7 @@ #include #include #include +#include #include #include @@ -658,7 +659,7 @@ static int init586(struct net_device *dev) s = jiffies; /* warning: only active with interrupts on !! */ while (!(cfg_cmd->cmd_status & STAT_COMPL)) { - if (jiffies - s > 30*HZ/100) + if (time_after(jiffies, s + 30*HZ/100)) break; } @@ -684,7 +685,7 @@ static int init586(struct net_device *dev) s = jiffies; while (!(ias_cmd->cmd_status & STAT_COMPL)) { - if (jiffies - s > 30*HZ/100) + if (time_after(jiffies, s + 30*HZ/100)) break; } @@ -709,7 +710,7 @@ static int init586(struct net_device *dev) s = jiffies; while (!(tdr_cmd->cmd_status & STAT_COMPL)) { - if (jiffies - s > 30*HZ/100) { + if (time_after(jiffies, s + 30*HZ/100)) { printk(KERN_WARNING "%s: %d Problems while running the TDR.\n", dev->name, __LINE__); result = 1; break; @@ -798,7 +799,7 @@ static int init586(struct net_device *dev) elmc_id_attn586(); s = jiffies; while (!(mc_cmd->cmd_status & STAT_COMPL)) { - if (jiffies - s > 30*HZ/100) + if (time_after(jiffies, s + 30*HZ/100)) break; } if (!(mc_cmd->cmd_status & STAT_COMPL)) { diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 7488ee7f7ca..3dde1df3348 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -258,6 +258,7 @@ static int vortex_debug = 1; #include #include #include +#include #include /* For NR_IRQS only. */ #include #include @@ -2717,7 +2718,7 @@ boomerang_rx(struct net_device *dev) skb = dev_alloc_skb(PKT_BUF_SZ); if (skb == NULL) { static unsigned long last_jif; - if ((jiffies - last_jif) > 10 * HZ) { + if (time_after(jiffies, last_jif + 10 * HZ)) { printk(KERN_WARNING "%s: memory shortage\n", dev->name); last_jif = jiffies; } diff --git a/drivers/net/apne.c b/drivers/net/apne.c index a94216b8718..b9820b86cdc 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -216,7 +217,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET); while ((inb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2*HZ/100) { + if (time_after(jiffies, reset_start_time + 2*HZ/100)) { printk(" not found (no reset ack).\n"); return -ENODEV; } @@ -382,7 +383,7 @@ apne_reset_8390(struct net_device *dev) /* This check _should_not_ be necessary, omit eventually. */ while ((inb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2*HZ/100) { + if (time_after(jiffies, reset_start_time + 2*HZ/100)) { printk("%s: ne_reset_8390() did not complete.\n", dev->name); break; } @@ -530,7 +531,7 @@ apne_block_output(struct net_device *dev, int count, dma_start = jiffies; while ((inb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0) - if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ + if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ printk("%s: timeout waiting for Tx RDC.\n", dev->name); apne_reset_8390(dev); NS8390_init(dev,1); diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 12ef52c193a..409d61d8d08 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -52,6 +52,7 @@ #include #include #include +#include /* "do nothing" functions for protocol drivers */ static void null_rx(struct net_device *dev, int bufnum, @@ -733,7 +734,7 @@ static void arcnet_timeout(struct net_device *dev) spin_unlock_irqrestore(&lp->lock, flags); - if (jiffies - lp->last_timeout > 10*HZ) { + if (time_after(jiffies, lp->last_timeout + 10*HZ)) { BUGMSG(D_EXTRA, "tx timed out%s (status=%Xh, intmask=%Xh, dest=%02Xh)\n", msg, status, lp->intmask, lp->lasttrans_dest); lp->last_timeout = jiffies; diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 6a93b666eb7..d52deb8d207 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -355,7 +356,7 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf dma_start = jiffies; while ((readb (addr + EN0_ISR) & ENISR_RDC) == 0) - if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ + if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ printk(KERN_ERR "%s: timeout waiting for TX RDC\n", dev->name); etherh_reset (dev); diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index f32a6b3acb2..b67545be2ca 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -161,6 +161,7 @@ static char *version = #include #include #include +#include #include #include @@ -754,7 +755,7 @@ static void eth16i_set_port(int ioaddr, int porttype) static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l) { - int starttime; + unsigned long starttime; outb(0xff, ioaddr + TX_STATUS_REG); @@ -765,7 +766,7 @@ static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l) outb(TX_START | 1, ioaddr + TRANSMIT_START_REG); while( (inb(ioaddr + TX_STATUS_REG) & 0x80) == 0) { - if( (jiffies - starttime) > TX_TIMEOUT) { + if( time_after(jiffies, starttime + TX_TIMEOUT)) { return -1; } } @@ -775,18 +776,18 @@ static int eth16i_send_probe_packet(int ioaddr, unsigned char *b, int l) static int eth16i_receive_probe_packet(int ioaddr) { - int starttime; + unsigned long starttime; starttime = jiffies; while((inb(ioaddr + TX_STATUS_REG) & 0x20) == 0) { - if( (jiffies - starttime) > TX_TIMEOUT) { + if( time_after(jiffies, starttime + TX_TIMEOUT)) { if(eth16i_debug > 1) printk(KERN_DEBUG "Timeout occurred waiting transmit packet received\n"); starttime = jiffies; while((inb(ioaddr + RX_STATUS_REG) & 0x80) == 0) { - if( (jiffies - starttime) > TX_TIMEOUT) { + if( time_after(jiffies, starttime + TX_TIMEOUT)) { if(eth16i_debug > 1) printk(KERN_DEBUG "Timeout occurred waiting receive packet\n"); return -1; diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index e4188d082f0..9220de9f4fe 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -905,7 +905,7 @@ static int epp_open(struct net_device *dev) /* autoprobe baud rate */ tstart = jiffies; i = 0; - while ((signed)(jiffies-tstart-HZ/3) < 0) { + while (time_before(jiffies, tstart + HZ/3)) { if (pp->ops->epp_read_addr(pp, &stat, 1, 0) != 1) goto epptimeout; if ((stat & (EPP_NRAEF|EPP_NRHF)) == EPP_NRHF) { diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 55c7ed60839..a37b82ebca3 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -115,6 +115,7 @@ #include #include #include +#include #include @@ -1499,7 +1500,7 @@ static int hp100_start_xmit_bm(struct sk_buff *skb, struct net_device *dev) printk("hp100: %s: start_xmit_bm: No TX PDL available.\n", dev->name); #endif /* not waited long enough since last tx? */ - if (jiffies - dev->trans_start < HZ) + if (time_before(jiffies, dev->trans_start + HZ)) return -EAGAIN; if (hp100_check_lan(dev)) @@ -1652,7 +1653,7 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev) printk("hp100: %s: start_xmit: tx free mem = 0x%x\n", dev->name, i); #endif /* not waited long enough since last failed tx try? */ - if (jiffies - dev->trans_start < HZ) { + if (time_before(jiffies, dev->trans_start + HZ)) { #ifdef HP100_DEBUG printk("hp100: %s: trans_start timing problem\n", dev->name); diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index 8f40368cf2e..aaebd28a192 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -27,6 +27,7 @@ static const char version1[] = #include #include #include +#include #include #include @@ -365,7 +366,7 @@ static void ne_reset_8390(struct net_device *dev) /* This check _should_not_ be necessary, omit eventually. */ while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2*HZ/100) { + if (time_after(jiffies, reset_start_time + 2*HZ/100)) { printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name); break; } @@ -580,7 +581,7 @@ retry: #endif while ((inb_p(NE_BASE + EN0_ISR) & ENISR_RDC) == 0) - if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ + if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name); ne_reset_8390(dev); NS8390_init(dev,1); diff --git a/drivers/net/ne.c b/drivers/net/ne.c index 94f782d51f0..08b218c5bfb 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -50,6 +50,7 @@ static const char version2[] = #include #include #include +#include #include #include @@ -341,7 +342,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET); while ((inb_p(ioaddr + EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2*HZ/100) { + if (time_after(jiffies, reset_start_time + 2*HZ/100)) { if (bad_card) { printk(" (warning: no reset ack)"); break; @@ -580,7 +581,7 @@ static void ne_reset_8390(struct net_device *dev) /* This check _should_not_ be necessary, omit eventually. */ while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2*HZ/100) { + if (time_after(jiffies, reset_start_time + 2*HZ/100)) { printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name); break; } @@ -787,7 +788,7 @@ retry: #endif while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) - if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ + if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ printk(KERN_WARNING "%s: timeout waiting for Tx RDC.\n", dev->name); ne_reset_8390(dev); NS8390_init(dev,1); diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index e6df375a1d4..2aa7b77f84f 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -75,6 +75,7 @@ static const char *version = "ne2.c:v0.91 Nov 16 1998 Wim Dumon #include #include +#include #include #include @@ -395,7 +396,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot) outb(inb(base_addr + NE_RESET), base_addr + NE_RESET); while ((inb_p(base_addr + EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2*HZ/100) { + if (time_after(jiffies, reset_start_time + 2*HZ/100)) { printk(" not found (no reset ack).\n"); retval = -ENODEV; goto out; @@ -548,7 +549,7 @@ static void ne_reset_8390(struct net_device *dev) /* This check _should_not_ be necessary, omit eventually. */ while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2*HZ/100) { + if (time_after(jiffies, reset_start_time + 2*HZ/100)) { printk("%s: ne_reset_8390() did not complete.\n", dev->name); break; @@ -749,7 +750,7 @@ retry: #endif while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) - if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ + if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ printk("%s: timeout waiting for Tx RDC.\n", dev->name); ne_reset_8390(dev); NS8390_init(dev,1); diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index b0c3b6ab626..253cf018dfb 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -116,6 +116,7 @@ #include #include #include +#include #include #include @@ -1607,7 +1608,7 @@ static void ns83820_run_bist(struct net_device *ndev, const char *name, u32 enab { struct ns83820 *dev = PRIV(ndev); int timed_out = 0; - long start; + unsigned long start; u32 status; int loops = 0; @@ -1625,7 +1626,7 @@ static void ns83820_run_bist(struct net_device *ndev, const char *name, u32 enab break; if (status & fail) break; - if ((jiffies - start) >= HZ) { + if (time_after_eq(jiffies, start + HZ)) { timed_out = 1; break; } diff --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c index 62167a29deb..d0f686d6eaa 100644 --- a/drivers/net/oaknet.c +++ b/drivers/net/oaknet.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -606,7 +607,7 @@ retry: #endif while ((ei_ibp(base + EN0_ISR) & ENISR_RDC) == 0) { - if (jiffies - start > OAKNET_WAIT) { + if (time_after(jiffies, start + OAKNET_WAIT)) { printk("%s: timeout waiting for Tx RDC.\n", dev->name); oaknet_reset_8390(dev); NS8390_init(dev, TRUE); diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 1c3c9c666f7..c4abc9365f8 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -796,7 +797,7 @@ static void media_check(unsigned long arg) media = inw(ioaddr+WN4_MEDIA) & 0xc810; /* Ignore collisions unless we've had no irq's recently */ - if (jiffies - lp->last_irq < HZ) { + if (time_before(jiffies, lp->last_irq + HZ)) { media &= ~0x0010; } else { /* Try harder to detect carrier errors */ diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index aa6540b3946..23659fd7c3a 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -570,7 +571,7 @@ ppp_async_encode(struct asyncppp *ap) * character if necessary. */ if (islcp || flag_time == 0 - || jiffies - ap->last_xmit >= flag_time) + || time_after_eq(jiffies, ap->last_xmit + flag_time)) *buf++ = PPP_FLAG; ap->last_xmit = jiffies; fcs = PPP_INITFCS; diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 79dca398f3a..bcef03feb2f 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -46,6 +46,7 @@ static const char version[] = #include #include #include +#include #include #include @@ -699,7 +700,7 @@ static void hardware_send_packet(struct net_device * dev, char *buf, int length) int ioaddr = dev->base_addr; int status = inw(SEEQ_STATUS); int transmit_ptr = 0; - int tmp; + unsigned long tmp; if (net_debug>4) { printk("%s: send 0x%04x\n",dev->name,length); @@ -724,7 +725,7 @@ static void hardware_send_packet(struct net_device * dev, char *buf, int length) /* drain FIFO */ tmp = jiffies; - while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && (jiffies - tmp < HZ)) + while ( (((status=inw(SEEQ_STATUS)) & SEEQSTAT_FIFO_EMPTY) == 0) && time_before(jiffies, tmp + HZ)) mb(); /* doit ! */ diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c index 221354eea21..88e212043a4 100644 --- a/drivers/net/shaper.c +++ b/drivers/net/shaper.c @@ -83,6 +83,7 @@ #include #include #include +#include #include #include @@ -168,7 +169,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev) /* * Queue over time. Spill packet. */ - if(SHAPERCB(skb)->shapeclock-jiffies > SHAPER_LATENCY) { + if(time_after(SHAPERCB(skb)->shapeclock,jiffies + SHAPER_LATENCY)) { dev_kfree_skb(skb); shaper->stats.tx_dropped++; } else diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 97712c3c4e0..c58a4c31d0d 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -122,6 +122,7 @@ #include #include #include +#include #include @@ -512,7 +513,7 @@ static int streamer_reset(struct net_device *dev) while (!((readw(streamer_mmio + SISR)) & SISR_SRB_REPLY)) { msleep_interruptible(100); - if (jiffies - t > 40 * HZ) { + if (time_after(jiffies, t + 40 * HZ)) { printk(KERN_ERR "IBM PCI tokenring card not responding\n"); release_region(dev->base_addr, STREAMER_IO_SPACE); diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 05477d24fd4..23032a7bc0a 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -100,6 +100,7 @@ #include #include #include +#include #include @@ -307,7 +308,7 @@ static int __devinit olympic_init(struct net_device *dev) t=jiffies; while((readl(olympic_mmio+BCTL)) & BCTL_SOFTRESET) { schedule(); - if(jiffies-t > 40*HZ) { + if(time_after(jiffies, t + 40*HZ)) { printk(KERN_ERR "IBM PCI tokenring card not responding.\n"); return -ENODEV; } @@ -359,7 +360,7 @@ static int __devinit olympic_init(struct net_device *dev) t=jiffies; while (!readl(olympic_mmio+CLKCTL) & CLKCTL_PAUSE) { schedule() ; - if(jiffies-t > 2*HZ) { + if(time_after(jiffies, t + 2*HZ)) { printk(KERN_ERR "IBM Cardbus tokenring adapter not responsing.\n") ; return -ENODEV; } @@ -373,7 +374,7 @@ static int __devinit olympic_init(struct net_device *dev) t=jiffies; while(!((readl(olympic_mmio+SISR_RR)) & SISR_SRB_REPLY)) { schedule(); - if(jiffies-t > 15*HZ) { + if(time_after(jiffies, t + 15*HZ)) { printk(KERN_ERR "IBM PCI tokenring card not responding.\n"); return -ENODEV; } @@ -519,7 +520,7 @@ static int olympic_open(struct net_device *dev) olympic_priv->srb_queued=0; break; } - if ((jiffies-t) > 10*HZ) { + if (time_after(jiffies, t + 10*HZ)) { printk(KERN_WARNING "%s: SRB timed out. \n",dev->name) ; olympic_priv->srb_queued=0; break ; diff --git a/drivers/net/tulip/pnic.c b/drivers/net/tulip/pnic.c index d9980bde750..ca7e53246ad 100644 --- a/drivers/net/tulip/pnic.c +++ b/drivers/net/tulip/pnic.c @@ -16,6 +16,7 @@ #include #include +#include #include "tulip.h" @@ -68,7 +69,7 @@ void pnic_lnk_change(struct net_device *dev, int csr5) */ if (tulip_media_cap[dev->if_port] & MediaIsMII) return; - if (! tp->nwayset || jiffies - dev->trans_start > 1*HZ) { + if (! tp->nwayset || time_after(jiffies, dev->trans_start + 1*HZ)) { tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff); iowrite32(tp->csr6, ioaddr + CSR6); iowrite32(0x30, ioaddr + CSR12); diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 18baacfc5a2..18a44580b53 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -112,7 +112,7 @@ static const char StripVersion[] = "1.3A-STUART.CHESHIRE"; #include #include #include - +#include /************************************************************************/ /* Useful structures and definitions */ @@ -1569,7 +1569,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev) del_timer(&strip_info->idle_timer); - if (jiffies - strip_info->pps_timer > HZ) { + if (time_after(jiffies, strip_info->pps_timer + HZ)) { unsigned long t = jiffies - strip_info->pps_timer; unsigned long rx_pps_count = (strip_info->rx_pps_count * HZ * 8 + t / 2) / t; unsigned long tx_pps_count = (strip_info->tx_pps_count * HZ * 8 + t / 2) / t; diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index 8ab6e12153b..76102160359 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -151,7 +152,7 @@ static int __devinit zorro8390_init(struct net_device *dev, z_writeb(z_readb(ioaddr + NE_RESET), ioaddr + NE_RESET); while ((z_readb(ioaddr + NE_EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2*HZ/100) { + if (time_after(jiffies, reset_start_time + 2*HZ/100)) { printk(KERN_WARNING " not found (no reset ack).\n"); return -ENODEV; } @@ -273,7 +274,7 @@ static void zorro8390_reset_8390(struct net_device *dev) /* This check _should_not_ be necessary, omit eventually. */ while ((z_readb(NE_BASE+NE_EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2*HZ/100) { + if (time_after(jiffies, reset_start_time + 2*HZ/100)) { printk(KERN_WARNING "%s: ne_reset_8390() did not complete.\n", dev->name); break; @@ -400,7 +401,7 @@ static void zorro8390_block_output(struct net_device *dev, int count, dma_start = jiffies; while ((z_readb(NE_BASE + NE_EN0_ISR) & ENISR_RDC) == 0) - if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ + if (time_after(jiffies, dma_start + 2*HZ/100)) { /* 20ms */ printk(KERN_ERR "%s: timeout waiting for Tx RDC.\n", dev->name); zorro8390_reset_8390(dev); -- cgit v1.2.3 From f03aa2d89ad600a1ed21a223f196776f217cfe00 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 14 Jan 2006 03:10:22 +0100 Subject: [PATCH] drivers/net/arcnet/: possible cleanups This patch contains the following possible cleanups: - make needlessly global code static - arcnet.c: remove the unneeded EXPORT_SYMBOL(arc_proto_null) - arcnet.c: remove the unneeded EXPORT_SYMBOL(arcnet_dump_packet) To make Jeff happy, arcnet.c still prints arcnet: v3.93 BETA 2000/04/29 - by Avery Pennarun et al. Signed-off-by: Adrian Bunk Signed-off-by: Jeff Garzik --- drivers/net/arcnet/arc-rawmode.c | 2 +- drivers/net/arcnet/arcnet.c | 17 ++++++++++------- drivers/net/arcnet/rfc1051.c | 2 +- drivers/net/arcnet/rfc1201.c | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c index e1ea29b0cd1..e7555d4e6ff 100644 --- a/drivers/net/arcnet/arc-rawmode.c +++ b/drivers/net/arcnet/arc-rawmode.c @@ -42,7 +42,7 @@ static int build_header(struct sk_buff *skb, struct net_device *dev, static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum); -struct ArcProto rawmode_proto = +static struct ArcProto rawmode_proto = { .suffix = 'r', .mtu = XMTU, diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index 409d61d8d08..64e2caf3083 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -62,6 +62,7 @@ static int null_build_header(struct sk_buff *skb, struct net_device *dev, static int null_prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum); +static void arcnet_rx(struct net_device *dev, int bufnum); /* * one ArcProto per possible proto ID. None of the elements of @@ -72,7 +73,7 @@ static int null_prepare_tx(struct net_device *dev, struct archdr *pkt, struct ArcProto *arc_proto_map[256], *arc_proto_default, *arc_bcast_proto, *arc_raw_proto; -struct ArcProto arc_proto_null = +static struct ArcProto arc_proto_null = { .suffix = '?', .mtu = XMTU, @@ -91,7 +92,6 @@ EXPORT_SYMBOL(arc_proto_map); EXPORT_SYMBOL(arc_proto_default); EXPORT_SYMBOL(arc_bcast_proto); EXPORT_SYMBOL(arc_raw_proto); -EXPORT_SYMBOL(arc_proto_null); EXPORT_SYMBOL(arcnet_unregister_proto); EXPORT_SYMBOL(arcnet_debug); EXPORT_SYMBOL(alloc_arcdev); @@ -119,7 +119,7 @@ static int __init arcnet_init(void) arcnet_debug = debug; - printk(VERSION); + printk("arcnet loaded.\n"); #ifdef ALPHA_WARNING BUGLVL(D_EXTRA) { @@ -179,8 +179,8 @@ EXPORT_SYMBOL(arcnet_dump_skb); * Dump the contents of an ARCnet buffer */ #if (ARCNET_DEBUG_MAX & (D_RX | D_TX)) -void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc, - int take_arcnet_lock) +static void arcnet_dump_packet(struct net_device *dev, int bufnum, + char *desc, int take_arcnet_lock) { struct arcnet_local *lp = dev->priv; int i, length; @@ -209,7 +209,10 @@ void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc, } -EXPORT_SYMBOL(arcnet_dump_packet); +#else + +#define arcnet_dump_packet(dev, bufnum, desc,take_arcnet_lock) do { } while (0) + #endif @@ -997,7 +1000,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs) * This is a generic packet receiver that calls arcnet??_rx depending on the * protocol ID found. */ -void arcnet_rx(struct net_device *dev, int bufnum) +static void arcnet_rx(struct net_device *dev, int bufnum) { struct arcnet_local *lp = dev->priv; struct archdr pkt; diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c index 6d7913704fb..6d6c69f036e 100644 --- a/drivers/net/arcnet/rfc1051.c +++ b/drivers/net/arcnet/rfc1051.c @@ -43,7 +43,7 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum); -struct ArcProto rfc1051_proto = +static struct ArcProto rfc1051_proto = { .suffix = 's', .mtu = XMTU - RFC1051_HDR_SIZE, diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c index 6b6ae4bf3d3..bee34226abf 100644 --- a/drivers/net/arcnet/rfc1201.c +++ b/drivers/net/arcnet/rfc1201.c @@ -43,7 +43,7 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum); static int continue_tx(struct net_device *dev, int bufnum); -struct ArcProto rfc1201_proto = +static struct ArcProto rfc1201_proto = { .suffix = 'a', .mtu = 1500, /* could be more, but some receivers can't handle it... */ -- cgit v1.2.3 From 26df54bffd90977fbc6fe8284f2beaed19fea44f Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 14 Jan 2006 03:09:40 +0100 Subject: [PATCH] drivers/net/s2io.c: make code static This patch makes some needlessly global code static. Signed-off-by: Adrian Bunk Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 22 +++++++++++----------- drivers/net/s2io.h | 17 +++++++---------- 2 files changed, 18 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 89c46787676..41c75616e91 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -72,8 +72,8 @@ static char s2io_driver_name[] = "Neterion"; static char s2io_driver_version[] = DRV_VERSION; -int rxd_size[4] = {32,48,48,64}; -int rxd_count[4] = {127,85,85,63}; +static int rxd_size[4] = {32,48,48,64}; +static int rxd_count[4] = {127,85,85,63}; static inline int RXD_IS_UP2DT(RxD_t *rxdp) { @@ -2127,7 +2127,7 @@ static void stop_nic(struct s2io_nic *nic) } } -int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb) +static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb) { struct net_device *dev = nic->dev; struct sk_buff *frag_list; @@ -2852,7 +2852,7 @@ static int wait_for_cmd_complete(nic_t * sp) * void. */ -void s2io_reset(nic_t * sp) +static void s2io_reset(nic_t * sp) { XENA_dev_config_t __iomem *bar0 = sp->bar0; u64 val64; @@ -2940,7 +2940,7 @@ void s2io_reset(nic_t * sp) * SUCCESS on success and FAILURE on failure. */ -int s2io_set_swapper(nic_t * sp) +static int s2io_set_swapper(nic_t * sp) { struct net_device *dev = sp->dev; XENA_dev_config_t __iomem *bar0 = sp->bar0; @@ -3089,7 +3089,7 @@ static int wait_for_msix_trans(nic_t *nic, int i) return ret; } -void restore_xmsi_data(nic_t *nic) +static void restore_xmsi_data(nic_t *nic) { XENA_dev_config_t __iomem *bar0 = nic->bar0; u64 val64; @@ -3180,7 +3180,7 @@ int s2io_enable_msi(nic_t *nic) return 0; } -int s2io_enable_msi_x(nic_t *nic) +static int s2io_enable_msi_x(nic_t *nic) { XENA_dev_config_t __iomem *bar0 = nic->bar0; u64 tx_mat, rx_mat; @@ -4128,7 +4128,7 @@ static void s2io_set_multicast(struct net_device *dev) * as defined in errno.h file on failure. */ -int s2io_set_mac_addr(struct net_device *dev, u8 * addr) +static int s2io_set_mac_addr(struct net_device *dev, u8 * addr) { nic_t *sp = dev->priv; XENA_dev_config_t __iomem *bar0 = sp->bar0; @@ -5713,7 +5713,7 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) * void. */ -void s2io_link(nic_t * sp, int link) +static void s2io_link(nic_t * sp, int link) { struct net_device *dev = (struct net_device *) sp->dev; @@ -5738,7 +5738,7 @@ void s2io_link(nic_t * sp, int link) * returns the revision ID of the device. */ -int get_xena_rev_id(struct pci_dev *pdev) +static int get_xena_rev_id(struct pci_dev *pdev) { u8 id = 0; int ret; @@ -6343,7 +6343,7 @@ int __init s2io_starter(void) * Description: This function is the cleanup routine for the driver. It unregist * ers the driver. */ -void s2io_closer(void) +static void s2io_closer(void) { pci_unregister_driver(&s2io_driver); DBG_PRINT(INIT_DBG, "cleanup done\n"); diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 852a6a899d0..68ae3365194 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -64,7 +64,7 @@ typedef enum xena_max_outstanding_splits { #define INTR_DBG 4 /* Global variable that defines the present debug level of the driver. */ -int debug_level = ERR_DBG; /* Default level. */ +static int debug_level = ERR_DBG; /* DEBUG message print. */ #define DBG_PRINT(dbg_level, args...) if(!(debug_level Date: Tue, 17 Jan 2006 22:52:51 +0100 Subject: [PATCH] starfire: Implement suspend/resume This patch implements suspend and resume methods for the starfire driver. It allows me to put my desktop PC with a starfire dual board into S4. Signed-Off-By: Stefan Rompf Signed-off-by: Jeff Garzik --- drivers/net/starfire.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index d167deda9a5..ed5458c4544 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -2084,6 +2084,38 @@ static int netdev_close(struct net_device *dev) return 0; } +#ifdef CONFIG_PM +static int starfire_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (netif_running(dev)) { + netif_device_detach(dev); + netdev_close(dev); + } + + pci_save_state(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev,state)); + + return 0; +} + +static int starfire_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + if (netif_running(dev)) { + netdev_open(dev); + netif_device_attach(dev); + } + + return 0; +} +#endif /* CONFIG_PM */ + static void __devexit starfire_remove_one (struct pci_dev *pdev) { @@ -2115,6 +2147,10 @@ static struct pci_driver starfire_driver = { .name = DRV_NAME, .probe = starfire_init_one, .remove = __devexit_p(starfire_remove_one), +#ifdef CONFIG_PM + .suspend = starfire_suspend, + .resume = starfire_resume, +#endif /* CONFIG_PM */ .id_table = starfire_pci_tbl, }; -- cgit v1.2.3 From 0d615ec2bb1cb8c38087bb24f6d2876dec3a9751 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 26 Jan 2006 22:01:38 -0500 Subject: sundance: Really read addr 0 Make phy 0 actually be read, as it is not being right now as we have: int mii_status = mdio_read(dev, phy, MII_BMSR); int phyx = phy & 0x1f; When we should have instead: int phyx = phy & 0x1f; int mii_status = mdio_read(dev, phyx, MII_BMSR); so that when phy, in the end of the (phy = 1; phy <= 32...) loop gets to 32 phyx gets to 0, i.e. we were reading at 32, when the intended read was for 0. Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Jeff Garzik --- drivers/net/sundance.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 0ab9c38b4a3..8cdeb5cbab5 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -633,9 +633,13 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, np->phys[0] = 1; /* Default setting */ np->mii_preamble_required++; + /* + * It seems some phys doesn't deal well with address 0 being accessed + * first, so leave address zero to the end of the loop (32 & 31). + */ for (phy = 1; phy <= 32 && phy_idx < MII_CNT; phy++) { - int mii_status = mdio_read(dev, phy, MII_BMSR); int phyx = phy & 0x1f; + int mii_status = mdio_read(dev, phyx, MII_BMSR); if (mii_status != 0xffff && mii_status != 0x0000) { np->phys[phy_idx++] = phyx; np->mii_if.advertising = mdio_read(dev, phyx, MII_ADVERTISE); -- cgit v1.2.3 From a707cd6e2d0a8c21dd8aeef8e4a0c0ccf8774fa9 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn / snakebyte Date: Thu, 26 Jan 2006 22:02:51 +0100 Subject: [PATCH] BUG_ON() Conversion in net/tulip/xircom_cb.c hi, this changes if() BUG(); constructs to BUG_ON() which is cleaner and can better optimized away Signed-off-by: Eric Sesterhenn Signed-off-by: Jeff Garzik --- drivers/net/tulip/xircom_cb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 60d1e05ab73..c5c738a51ee 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -598,10 +598,8 @@ static void setup_descriptors(struct xircom_private *card) enter("setup_descriptors"); - if (card->rx_buffer == NULL) - BUG(); - if (card->tx_buffer == NULL) - BUG(); + BUG_ON(card->rx_buffer == NULL); + BUG_ON(card->tx_buffer == NULL); /* Receive descriptors */ memset(card->rx_buffer, 0, 128); /* clear the descriptors */ -- cgit v1.2.3 From 7e0b58f32fb5e9c958078a6d722a7d0b230346a7 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn / snakebyte Date: Thu, 26 Jan 2006 22:02:43 +0100 Subject: [PATCH] BUG_ON() Conversion in net/tulip/de2104x.c hi, this changes if() BUG(); constructs to BUG_ON() which is cleaner and can better optimized away One of the if()s contains a call to de_is_running(), which seems to be safe to replace, but someone with more knownledge of the code might want to verify this... Signed-off-by: Eric Sesterhenn Signed-off-by: Jeff Garzik --- drivers/net/tulip/de2104x.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index d7fb3ffe06a..d6c3d52d2e8 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -402,8 +402,7 @@ static void de_rx (struct de_private *de) unsigned copying_skb, buflen; skb = de->rx_skb[rx_tail].skb; - if (!skb) - BUG(); + BUG_ON(!skb); rmb(); status = le32_to_cpu(de->rx_ring[rx_tail].opts1); if (status & DescOwn) @@ -545,8 +544,7 @@ static void de_tx (struct de_private *de) break; skb = de->tx_skb[tx_tail].skb; - if (!skb) - BUG(); + BUG_ON(!skb); if (unlikely(skb == DE_DUMMY_SKB)) goto next; @@ -789,8 +787,7 @@ static void __de_set_rx_mode (struct net_device *dev) de->tx_head = NEXT_TX(entry); - if (TX_BUFFS_AVAIL(de) < 0) - BUG(); + BUG_ON(TX_BUFFS_AVAIL(de) < 0); if (TX_BUFFS_AVAIL(de) == 0) netif_stop_queue(dev); @@ -916,8 +913,7 @@ static void de_set_media (struct de_private *de) unsigned media = de->media_type; u32 macmode = dr32(MacMode); - if (de_is_running(de)) - BUG(); + BUG_ON(de_is_running(de)); if (de->de21040) dw32(CSR11, FULL_DUPLEX_MAGIC); @@ -1153,8 +1149,7 @@ static void de_media_interrupt (struct de_private *de, u32 status) return; } - if (!(status & LinkFail)) - BUG(); + BUG_ON(!(status & LinkFail)); if (netif_carrier_ok(de->dev)) { de_link_down(de); @@ -2092,8 +2087,7 @@ static void __exit de_remove_one (struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); struct de_private *de = dev->priv; - if (!dev) - BUG(); + BUG_ON(!dev); unregister_netdev(dev); kfree(de->ee_data); iounmap(de->regs); -- cgit v1.2.3 From cca4aa83c79bcd571b06c83c50ea63cb75f1c2bb Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn / snakebyte Date: Thu, 26 Jan 2006 22:02:49 +0100 Subject: [PATCH] BUG_ON() Conversion in net/tulip/winbond-840.c hi, this changes if() BUG(); constructs to BUG_ON() which is cleaner and can better optimized away Signed-off-by: Eric Sesterhenn Signed-off-by: Jeff Garzik --- drivers/net/tulip/winbond-840.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 5b1af3986ab..ba05dedf29d 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -1645,7 +1645,7 @@ static int w840_suspend (struct pci_dev *pdev, pm_message_t state) /* no more hardware accesses behind this line. */ - if (np->csr6) BUG(); + BUG_ON(np->csr6); if (ioread32(ioaddr + IntrEnable)) BUG(); /* pci_power_off(pdev, -1); */ -- cgit v1.2.3 From 7d3d0439f574a4857c97b3ad2e63b082b7382d7e Mon Sep 17 00:00:00 2001 From: Ravinandan Arakali Date: Wed, 25 Jan 2006 14:53:07 -0500 Subject: [PATCH] S2io: Large Receive Offload (LRO) feature(v2) for Neterion (s2io) 10GbE Xframe PCI-X and PCI-E NICs Hi, Below is a patch for the Large Receive Offload feature. Please review and let us know your comments. LRO algorithm was described in an OLS 2005 presentation, located at ftp.s2io.com user: linuxdocs password: HALdocs The same ftp site has Programming Manual for Xframe-I ASIC. LRO feature is supported on Neterion Xframe-I, Xframe-II and Xframe-Express 10GbE NICs. Brief description: The Large Receive Offload(LRO) feature is a stateless offload that is complementary to TSO feature but on the receive path. The idea is to combine and collapse(upto 64K maximum) in the driver, in-sequence TCP packets belonging to the same session. It is mainly designed to improve 1500 mtu receive performance, since Jumbo frame performance is already close to 10GbE line rate. Some performance numbers are attached below. Implementation details: 1. Handle packet chains from multiple sessions(current default MAX_LRO_SESSSIONS=32). 2. Examine each packet for eligiblity to aggregate. A packet is considered eligible if it meets all the below criteria. a. It is a TCP/IP packet and L2 type is not LLC or SNAP. b. The packet has no checksum errors(L3 and L4). c. There are no IP options. The only TCP option supported is timestamps. d. Search and locate the LRO object corresponding to this socket and ensure packet is in TCP sequence. e. It's not a special packet(SYN, FIN, RST, URG, PSH etc. flags are not set). f. TCP payload is non-zero(It's not a pure ACK). g. It's not an IP-fragmented packet. 3. If a packet is found eligible, the LRO object is updated with information such as next sequence number expected, current length of aggregated packet and so on. If not eligible or max packets reached, update IP and TCP headers of first packet in the chain and pass it up to stack. 4. The frag_list in skb structure is used to chain packets into one large packet. Kernel changes required: None Performance results: Main focus of the initial testing was on 1500 mtu receiver, since this is a bottleneck not covered by the existing stateless offloads. There are couple disclaimers about the performance results below: 1. Your mileage will vary!!!! We initially concentrated on couple pci-x 2.0 platforms that are powerful enough to push 10 GbE NIC and do not have bottlenecks other than cpu%; testing on other platforms is still in progress. On some lower end systems we are seeing lower gains. 2. Current LRO implementation is still (for the most part) software based, and therefore performance potential of the feature is far from being realized. Full hw implementation of LRO is expected in the next version of Xframe ASIC. Performance delta(with MTU=1500) going from LRO disabled to enabled: IBM 2-way Xeon (x366) : 3.5 to 7.1 Gbps 2-way Opteron : 4.5 to 6.1 Gbps Signed-off-by: Ravinandan Arakali Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 586 +++++++++++++++++++++++++++++++++++++++++++++++------ drivers/net/s2io.h | 38 ++++ 2 files changed, 562 insertions(+), 62 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 49b597cbc19..4e392914971 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -57,6 +57,9 @@ #include #include #include +#include +#include +#include #include #include @@ -66,7 +69,7 @@ #include "s2io.h" #include "s2io-regs.h" -#define DRV_VERSION "Version 2.0.9.4" +#define DRV_VERSION "2.0.11.2" /* S2io Driver name & version. */ static char s2io_driver_name[] = "Neterion"; @@ -168,6 +171,11 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { {"\n DRIVER STATISTICS"}, {"single_bit_ecc_errs"}, {"double_bit_ecc_errs"}, + ("lro_aggregated_pkts"), + ("lro_flush_both_count"), + ("lro_out_of_sequence_pkts"), + ("lro_flush_due_to_max_pkts"), + ("lro_avg_aggr_pkts"), }; #define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN @@ -317,6 +325,12 @@ static unsigned int indicate_max_pkts; static unsigned int rxsync_frequency = 3; /* Interrupt type. Values can be 0(INTA), 1(MSI), 2(MSI_X) */ static unsigned int intr_type = 0; +/* Large receive offload feature */ +static unsigned int lro = 0; +/* Max pkts to be aggregated by LRO at one time. If not specified, + * aggregation happens until we hit max IP pkt size(64K) + */ +static unsigned int lro_max_pkts = 0xFFFF; /* * S2IO device table. @@ -1476,6 +1490,19 @@ static int init_nic(struct s2io_nic *nic) writel((u32) (val64 >> 32), (add + 4)); val64 = readq(&bar0->mac_cfg); + /* Enable FCS stripping by adapter */ + add = &bar0->mac_cfg; + val64 = readq(&bar0->mac_cfg); + val64 |= MAC_CFG_RMAC_STRIP_FCS; + if (nic->device_type == XFRAME_II_DEVICE) + writeq(val64, &bar0->mac_cfg); + else { + writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); + writel((u32) (val64), add); + writeq(RMAC_CFG_KEY(0x4C0D), &bar0->rmac_cfg_key); + writel((u32) (val64 >> 32), (add + 4)); + } + /* * Set the time value to be inserted in the pause frame * generated by xena. @@ -2569,6 +2596,8 @@ static void rx_intr_handler(ring_info_t *ring_data) #ifndef CONFIG_S2IO_NAPI int pkt_cnt = 0; #endif + int i; + spin_lock(&nic->rx_lock); if (atomic_read(&nic->card_state) == CARD_DOWN) { DBG_PRINT(INTR_DBG, "%s: %s going down for reset\n", @@ -2661,6 +2690,18 @@ static void rx_intr_handler(ring_info_t *ring_data) break; #endif } + if (nic->lro) { + /* Clear all LRO sessions before exiting */ + for (i=0; ilro0_n[i]; + if (lro->in_use) { + update_L3L4_header(nic, lro); + queue_rx_frame(lro->parent); + clear_lro_session(lro); + } + } + } + spin_unlock(&nic->rx_lock); } @@ -3668,23 +3709,32 @@ s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs) * else schedule a tasklet to reallocate the buffers. */ for (i = 0; i < config->rx_ring_num; i++) { - int rxb_size = atomic_read(&sp->rx_bufs_left[i]); - int level = rx_buffer_level(sp, rxb_size, i); - - if ((level == PANIC) && (!TASKLET_IN_USE)) { - DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name); - DBG_PRINT(INTR_DBG, "PANIC levels\n"); - if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) { - DBG_PRINT(ERR_DBG, "%s:Out of memory", - dev->name); - DBG_PRINT(ERR_DBG, " in ISR!!\n"); + if (!sp->lro) { + int rxb_size = atomic_read(&sp->rx_bufs_left[i]); + int level = rx_buffer_level(sp, rxb_size, i); + + if ((level == PANIC) && (!TASKLET_IN_USE)) { + DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", + dev->name); + DBG_PRINT(INTR_DBG, "PANIC levels\n"); + if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) { + DBG_PRINT(ERR_DBG, "%s:Out of memory", + dev->name); + DBG_PRINT(ERR_DBG, " in ISR!!\n"); + clear_bit(0, (&sp->tasklet_status)); + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; + } clear_bit(0, (&sp->tasklet_status)); - atomic_dec(&sp->isr_cnt); - return IRQ_HANDLED; + } else if (level == LOW) { + tasklet_schedule(&sp->task); } - clear_bit(0, (&sp->tasklet_status)); - } else if (level == LOW) { - tasklet_schedule(&sp->task); + } + else if (fill_rx_buffers(sp, i) == -ENOMEM) { + DBG_PRINT(ERR_DBG, "%s:Out of memory", + dev->name); + DBG_PRINT(ERR_DBG, " in Rx Intr!!\n"); + break; } } @@ -3697,29 +3747,37 @@ s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs) { ring_info_t *ring = (ring_info_t *)dev_id; nic_t *sp = ring->nic; + struct net_device *dev = (struct net_device *) dev_id; int rxb_size, level, rng_n; atomic_inc(&sp->isr_cnt); rx_intr_handler(ring); rng_n = ring->ring_no; - rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]); - level = rx_buffer_level(sp, rxb_size, rng_n); - - if ((level == PANIC) && (!TASKLET_IN_USE)) { - int ret; - DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__); - DBG_PRINT(INTR_DBG, "PANIC levels\n"); - if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) { - DBG_PRINT(ERR_DBG, "Out of memory in %s", - __FUNCTION__); + if (!sp->lro) { + rxb_size = atomic_read(&sp->rx_bufs_left[rng_n]); + level = rx_buffer_level(sp, rxb_size, rng_n); + + if ((level == PANIC) && (!TASKLET_IN_USE)) { + int ret; + DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__); + DBG_PRINT(INTR_DBG, "PANIC levels\n"); + if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) { + DBG_PRINT(ERR_DBG, "Out of memory in %s", + __FUNCTION__); + clear_bit(0, (&sp->tasklet_status)); + return IRQ_HANDLED; + } clear_bit(0, (&sp->tasklet_status)); - return IRQ_HANDLED; + } else if (level == LOW) { + tasklet_schedule(&sp->task); } - clear_bit(0, (&sp->tasklet_status)); - } else if (level == LOW) { - tasklet_schedule(&sp->task); } + else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) { + DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name); + DBG_PRINT(ERR_DBG, " in Rx Intr!!\n"); + } + atomic_dec(&sp->isr_cnt); return IRQ_HANDLED; @@ -3875,24 +3933,33 @@ static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs) */ #ifndef CONFIG_S2IO_NAPI for (i = 0; i < config->rx_ring_num; i++) { - int ret; - int rxb_size = atomic_read(&sp->rx_bufs_left[i]); - int level = rx_buffer_level(sp, rxb_size, i); - - if ((level == PANIC) && (!TASKLET_IN_USE)) { - DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", dev->name); - DBG_PRINT(INTR_DBG, "PANIC levels\n"); - if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) { - DBG_PRINT(ERR_DBG, "%s:Out of memory", - dev->name); - DBG_PRINT(ERR_DBG, " in ISR!!\n"); + if (!sp->lro) { + int ret; + int rxb_size = atomic_read(&sp->rx_bufs_left[i]); + int level = rx_buffer_level(sp, rxb_size, i); + + if ((level == PANIC) && (!TASKLET_IN_USE)) { + DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", + dev->name); + DBG_PRINT(INTR_DBG, "PANIC levels\n"); + if ((ret = fill_rx_buffers(sp, i)) == -ENOMEM) { + DBG_PRINT(ERR_DBG, "%s:Out of memory", + dev->name); + DBG_PRINT(ERR_DBG, " in ISR!!\n"); + clear_bit(0, (&sp->tasklet_status)); + atomic_dec(&sp->isr_cnt); + return IRQ_HANDLED; + } clear_bit(0, (&sp->tasklet_status)); - atomic_dec(&sp->isr_cnt); - return IRQ_HANDLED; + } else if (level == LOW) { + tasklet_schedule(&sp->task); } - clear_bit(0, (&sp->tasklet_status)); - } else if (level == LOW) { - tasklet_schedule(&sp->task); + } + else if (fill_rx_buffers(sp, i) == -ENOMEM) { + DBG_PRINT(ERR_DBG, "%s:Out of memory", + dev->name); + DBG_PRINT(ERR_DBG, " in Rx intr!!\n"); + break; } } #endif @@ -5134,6 +5201,16 @@ static void s2io_get_ethtool_stats(struct net_device *dev, tmp_stats[i++] = 0; tmp_stats[i++] = stat_info->sw_stat.single_ecc_errs; tmp_stats[i++] = stat_info->sw_stat.double_ecc_errs; + tmp_stats[i++] = stat_info->sw_stat.clubbed_frms_cnt; + tmp_stats[i++] = stat_info->sw_stat.sending_both; + tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts; + tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts; + if (stat_info->sw_stat.num_aggregations) + tmp_stats[i++] = stat_info->sw_stat.sum_avg_pkts_aggregated / + stat_info->sw_stat.num_aggregations; + else + tmp_stats[i++] = 0; + } static int s2io_ethtool_get_regs_len(struct net_device *dev) @@ -5515,6 +5592,14 @@ static int s2io_card_up(nic_t * sp) /* Setting its receive mode */ s2io_set_multicast(dev); + if (sp->lro) { + /* Initialize max aggregatable pkts based on MTU */ + sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu; + /* Check if we can use(if specified) user provided value */ + if (lro_max_pkts < sp->lro_max_aggr_per_sess) + sp->lro_max_aggr_per_sess = lro_max_pkts; + } + /* Enable tasklet for the device */ tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev); @@ -5607,6 +5692,7 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) ((unsigned long) rxdp->Host_Control); int ring_no = ring_data->ring_no; u16 l3_csum, l4_csum; + lro_t *lro; skb->dev = dev; if (rxdp->Control_1 & RXD_T_CODE) { @@ -5655,7 +5741,8 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) skb_put(skb, buf2_len); } - if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && + if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) || + (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) && (sp->rx_csum)) { l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1); l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); @@ -5666,6 +5753,54 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) * a flag in the RxD. */ skb->ip_summed = CHECKSUM_UNNECESSARY; + if (sp->lro) { + u32 tcp_len; + u8 *tcp; + int ret = 0; + + ret = s2io_club_tcp_session(skb->data, &tcp, + &tcp_len, &lro, rxdp, sp); + switch (ret) { + case 3: /* Begin anew */ + lro->parent = skb; + goto aggregate; + case 1: /* Aggregate */ + { + lro_append_pkt(sp, lro, + skb, tcp_len); + goto aggregate; + } + case 4: /* Flush session */ + { + lro_append_pkt(sp, lro, + skb, tcp_len); + queue_rx_frame(lro->parent); + clear_lro_session(lro); + sp->mac_control.stats_info-> + sw_stat.flush_max_pkts++; + goto aggregate; + } + case 2: /* Flush both */ + lro->parent->data_len = + lro->frags_len; + sp->mac_control.stats_info-> + sw_stat.sending_both++; + queue_rx_frame(lro->parent); + clear_lro_session(lro); + goto send_up; + case 0: /* sessions exceeded */ + case 5: /* + * First pkt in session not + * L3/L4 aggregatable + */ + break; + default: + DBG_PRINT(ERR_DBG, + "%s: Samadhana!!\n", + __FUNCTION__); + BUG(); + } + } } else { /* * Packet with erroneous checksum, let the @@ -5677,25 +5812,31 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp) skb->ip_summed = CHECKSUM_NONE; } - skb->protocol = eth_type_trans(skb, dev); + if (!sp->lro) { + skb->protocol = eth_type_trans(skb, dev); #ifdef CONFIG_S2IO_NAPI - if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { - /* Queueing the vlan frame to the upper layer */ - vlan_hwaccel_receive_skb(skb, sp->vlgrp, - RXD_GET_VLAN_TAG(rxdp->Control_2)); - } else { - netif_receive_skb(skb); - } + if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { + /* Queueing the vlan frame to the upper layer */ + vlan_hwaccel_receive_skb(skb, sp->vlgrp, + RXD_GET_VLAN_TAG(rxdp->Control_2)); + } else { + netif_receive_skb(skb); + } #else - if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { - /* Queueing the vlan frame to the upper layer */ - vlan_hwaccel_rx(skb, sp->vlgrp, - RXD_GET_VLAN_TAG(rxdp->Control_2)); - } else { - netif_rx(skb); - } + if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) { + /* Queueing the vlan frame to the upper layer */ + vlan_hwaccel_rx(skb, sp->vlgrp, + RXD_GET_VLAN_TAG(rxdp->Control_2)); + } else { + netif_rx(skb); + } #endif + } else { +send_up: + queue_rx_frame(skb); + } dev->last_rx = jiffies; +aggregate: atomic_dec(&sp->rx_bufs_left[ring_no]); return SUCCESS; } @@ -5807,6 +5948,8 @@ module_param(indicate_max_pkts, int, 0); #endif module_param(rxsync_frequency, int, 0); module_param(intr_type, int, 0); +module_param(lro, int, 0); +module_param(lro_max_pkts, int, 0); /** * s2io_init_nic - Initialization of the adapter . @@ -5938,6 +6081,7 @@ Defaulting to INTA\n"); else sp->device_type = XFRAME_I_DEVICE; + sp->lro = lro; /* Initialize some PCI/PCI-X fields of the NIC. */ s2io_init_pci(sp); @@ -6241,6 +6385,10 @@ Defaulting to INTA\n"); DBG_PRINT(ERR_DBG, "%s: 3-Buffer mode support has been " "enabled\n",dev->name); + if (sp->lro) + DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n", + dev->name); + /* Initialize device name */ strcpy(sp->name, dev->name); if (sp->device_type & XFRAME_II_DEVICE) @@ -6351,3 +6499,317 @@ void s2io_closer(void) module_init(s2io_starter); module_exit(s2io_closer); + +static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, + struct tcphdr **tcp, RxD_t *rxdp) +{ + int ip_off; + u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len; + + if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) { + DBG_PRINT(INIT_DBG,"%s: Non-TCP frames not supported for LRO\n", + __FUNCTION__); + return -1; + } + + /* TODO: + * By default the VLAN field in the MAC is stripped by the card, if this + * feature is turned off in rx_pa_cfg register, then the ip_off field + * has to be shifted by a further 2 bytes + */ + switch (l2_type) { + case 0: /* DIX type */ + case 4: /* DIX type with VLAN */ + ip_off = HEADER_ETHERNET_II_802_3_SIZE; + break; + /* LLC, SNAP etc are considered non-mergeable */ + default: + return -1; + } + + *ip = (struct iphdr *)((u8 *)buffer + ip_off); + ip_len = (u8)((*ip)->ihl); + ip_len <<= 2; + *tcp = (struct tcphdr *)((unsigned long)*ip + ip_len); + + return 0; +} + +static int check_for_socket_match(lro_t *lro, struct iphdr *ip, + struct tcphdr *tcp) +{ + DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); + if ((lro->iph->saddr != ip->saddr) || (lro->iph->daddr != ip->daddr) || + (lro->tcph->source != tcp->source) || (lro->tcph->dest != tcp->dest)) + return -1; + return 0; +} + +static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp) +{ + return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2)); +} + +static void initiate_new_session(lro_t *lro, u8 *l2h, + struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len) +{ + DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); + lro->l2h = l2h; + lro->iph = ip; + lro->tcph = tcp; + lro->tcp_next_seq = tcp_pyld_len + ntohl(tcp->seq); + lro->tcp_ack = ntohl(tcp->ack_seq); + lro->sg_num = 1; + lro->total_len = ntohs(ip->tot_len); + lro->frags_len = 0; + /* + * check if we saw TCP timestamp. Other consistency checks have + * already been done. + */ + if (tcp->doff == 8) { + u32 *ptr; + ptr = (u32 *)(tcp+1); + lro->saw_ts = 1; + lro->cur_tsval = *(ptr+1); + lro->cur_tsecr = *(ptr+2); + } + lro->in_use = 1; +} + +static void update_L3L4_header(nic_t *sp, lro_t *lro) +{ + struct iphdr *ip = lro->iph; + struct tcphdr *tcp = lro->tcph; + u16 nchk; + StatInfo_t *statinfo = sp->mac_control.stats_info; + DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); + + /* Update L3 header */ + ip->tot_len = htons(lro->total_len); + ip->check = 0; + nchk = ip_fast_csum((u8 *)lro->iph, ip->ihl); + ip->check = nchk; + + /* Update L4 header */ + tcp->ack_seq = lro->tcp_ack; + tcp->window = lro->window; + + /* Update tsecr field if this session has timestamps enabled */ + if (lro->saw_ts) { + u32 *ptr = (u32 *)(tcp + 1); + *(ptr+2) = lro->cur_tsecr; + } + + /* Update counters required for calculation of + * average no. of packets aggregated. + */ + statinfo->sw_stat.sum_avg_pkts_aggregated += lro->sg_num; + statinfo->sw_stat.num_aggregations++; +} + +static void aggregate_new_rx(lro_t *lro, struct iphdr *ip, + struct tcphdr *tcp, u32 l4_pyld) +{ + DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); + lro->total_len += l4_pyld; + lro->frags_len += l4_pyld; + lro->tcp_next_seq += l4_pyld; + lro->sg_num++; + + /* Update ack seq no. and window ad(from this pkt) in LRO object */ + lro->tcp_ack = tcp->ack_seq; + lro->window = tcp->window; + + if (lro->saw_ts) { + u32 *ptr; + /* Update tsecr and tsval from this packet */ + ptr = (u32 *) (tcp + 1); + lro->cur_tsval = *(ptr + 1); + lro->cur_tsecr = *(ptr + 2); + } +} + +static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip, + struct tcphdr *tcp, u32 tcp_pyld_len) +{ + DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); + u8 *ptr; + + if (!tcp_pyld_len) { + /* Runt frame or a pure ack */ + return -1; + } + + if (ip->ihl != 5) /* IP has options */ + return -1; + + if (tcp->urg || tcp->psh || tcp->rst || tcp->syn || tcp->fin || + !tcp->ack) { + /* + * Currently recognize only the ack control word and + * any other control field being set would result in + * flushing the LRO session + */ + return -1; + } + + /* + * Allow only one TCP timestamp option. Don't aggregate if + * any other options are detected. + */ + if (tcp->doff != 5 && tcp->doff != 8) + return -1; + + if (tcp->doff == 8) { + ptr = (u8 *)(tcp + 1); + while (*ptr == TCPOPT_NOP) + ptr++; + if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP) + return -1; + + /* Ensure timestamp value increases monotonically */ + if (l_lro) + if (l_lro->cur_tsval > *((u32 *)(ptr+2))) + return -1; + + /* timestamp echo reply should be non-zero */ + if (*((u32 *)(ptr+6)) == 0) + return -1; + } + + return 0; +} + +static int +s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, + RxD_t *rxdp, nic_t *sp) +{ + struct iphdr *ip; + struct tcphdr *tcph; + int ret = 0, i; + + if (!(ret = check_L2_lro_capable(buffer, &ip, (struct tcphdr **)tcp, + rxdp))) { + DBG_PRINT(INFO_DBG,"IP Saddr: %x Daddr: %x\n", + ip->saddr, ip->daddr); + } else { + return ret; + } + + tcph = (struct tcphdr *)*tcp; + *tcp_len = get_l4_pyld_length(ip, tcph); + for (i=0; ilro0_n[i]; + if (l_lro->in_use) { + if (check_for_socket_match(l_lro, ip, tcph)) + continue; + /* Sock pair matched */ + *lro = l_lro; + + if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) { + DBG_PRINT(INFO_DBG, "%s:Out of order. expected " + "0x%x, actual 0x%x\n", __FUNCTION__, + (*lro)->tcp_next_seq, + ntohl(tcph->seq)); + + sp->mac_control.stats_info-> + sw_stat.outof_sequence_pkts++; + ret = 2; + break; + } + + if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,*tcp_len)) + ret = 1; /* Aggregate */ + else + ret = 2; /* Flush both */ + break; + } + } + + if (ret == 0) { + /* Before searching for available LRO objects, + * check if the pkt is L3/L4 aggregatable. If not + * don't create new LRO session. Just send this + * packet up. + */ + if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) { + return 5; + } + + for (i=0; ilro0_n[i]; + if (!(l_lro->in_use)) { + *lro = l_lro; + ret = 3; /* Begin anew */ + break; + } + } + } + + if (ret == 0) { /* sessions exceeded */ + DBG_PRINT(INFO_DBG,"%s:All LRO sessions already in use\n", + __FUNCTION__); + *lro = NULL; + return ret; + } + + switch (ret) { + case 3: + initiate_new_session(*lro, buffer, ip, tcph, *tcp_len); + break; + case 2: + update_L3L4_header(sp, *lro); + break; + case 1: + aggregate_new_rx(*lro, ip, tcph, *tcp_len); + if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) { + update_L3L4_header(sp, *lro); + ret = 4; /* Flush the LRO */ + } + break; + default: + DBG_PRINT(ERR_DBG,"%s:Dont know, can't say!!\n", + __FUNCTION__); + break; + } + + return ret; +} + +static void clear_lro_session(lro_t *lro) +{ + static u16 lro_struct_size = sizeof(lro_t); + + memset(lro, 0, lro_struct_size); +} + +static void queue_rx_frame(struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + + skb->protocol = eth_type_trans(skb, dev); +#ifdef CONFIG_S2IO_NAPI + netif_receive_skb(skb); +#else + netif_rx(skb); +#endif +} + +static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, + u32 tcp_len) +{ + struct sk_buff *tmp, *first = lro->parent; + + first->len += tcp_len; + first->data_len = lro->frags_len; + skb_pull(skb, (skb->len - tcp_len)); + if ((tmp = skb_shinfo(first)->frag_list)) { + while (tmp->next) + tmp = tmp->next; + tmp->next = skb; + } + else + skb_shinfo(first)->frag_list = skb; + sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++; + return; +} diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 852a6a899d0..65cc59ac71f 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h @@ -78,6 +78,13 @@ int debug_level = ERR_DBG; /* Default level. */ typedef struct { unsigned long long single_ecc_errs; unsigned long long double_ecc_errs; + /* LRO statistics */ + unsigned long long clubbed_frms_cnt; + unsigned long long sending_both; + unsigned long long outof_sequence_pkts; + unsigned long long flush_max_pkts; + unsigned long long sum_avg_pkts_aggregated; + unsigned long long num_aggregations; } swStat_t; /* The statistics block of Xena */ @@ -680,6 +687,24 @@ struct msix_info_st { u64 data; }; +/* Data structure to represent a LRO session */ +typedef struct lro { + struct sk_buff *parent; + u8 *l2h; + struct iphdr *iph; + struct tcphdr *tcph; + u32 tcp_next_seq; + u32 tcp_ack; + int total_len; + int frags_len; + int sg_num; + int in_use; + u16 window; + u32 cur_tsval; + u32 cur_tsecr; + u8 saw_ts; +}lro_t; + /* Structure representing one instance of the NIC */ struct s2io_nic { int rxd_mode; @@ -784,6 +809,13 @@ struct s2io_nic { #define XFRAME_II_DEVICE 2 u8 device_type; +#define MAX_LRO_SESSIONS 32 + lro_t lro0_n[MAX_LRO_SESSIONS]; + unsigned long clubbed_frms_cnt; + unsigned long sending_both; + u8 lro; + u16 lro_max_aggr_per_sess; + #define INTA 0 #define MSI 1 #define MSI_X 2 @@ -940,4 +972,10 @@ static void s2io_card_down(nic_t *nic); static int s2io_card_up(nic_t *nic); int get_xena_rev_id(struct pci_dev *pdev); void restore_xmsi_data(nic_t *nic); + +static int s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, RxD_t *rxdp, nic_t *sp); +static void clear_lro_session(lro_t *lro); +static void queue_rx_frame(struct sk_buff *skb); +static void update_L3L4_header(nic_t *sp, lro_t *lro); +static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 tcp_len); #endif /* _S2IO_H */ -- cgit v1.2.3 From ed9b5d457668392182659747a734b38e86820adb Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 27 Jan 2006 01:06:38 -0700 Subject: [PATCH] mv643xx_eth: Remove needless mp->port_mac_addr mp->port_mac_addr is just a redundant copy of dev->dev_addr, so remove it. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 18 +++++++----------- drivers/net/mv643xx_eth.h | 3 +-- 2 files changed, 8 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 7ef4b0434a3..af9bbe649fc 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -243,8 +243,7 @@ static void mv643xx_eth_update_mac_address(struct net_device *dev) unsigned int port_num = mp->port_num; eth_port_init_mac_tables(port_num); - memcpy(mp->port_mac_addr, dev->dev_addr, 6); - eth_port_uc_addr_set(port_num, mp->port_mac_addr); + eth_port_uc_addr_set(port_num, dev->dev_addr); } /* @@ -320,7 +319,7 @@ static void mv643xx_eth_tx_timeout_task(struct net_device *dev) netif_device_detach(dev); eth_port_reset(mp->port_num); - eth_port_start(mp); + eth_port_start(dev); netif_device_attach(dev); } @@ -751,9 +750,6 @@ static int mv643xx_eth_open(struct net_device *dev) /* Stop RX Queues */ mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), 0x0000ff00); - /* Set the MAC Address */ - memcpy(mp->port_mac_addr, dev->dev_addr, 6); - eth_port_init(mp); INIT_WORK(&mp->rx_task, (void (*)(void *))mv643xx_eth_rx_task, dev); @@ -839,7 +835,7 @@ static int mv643xx_eth_open(struct net_device *dev) mv643xx_eth_rx_task(dev); /* Fill RX ring with skb's */ - eth_port_start(mp); + eth_port_start(dev); /* Interrupt Coalescing */ @@ -1706,7 +1702,6 @@ MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX"); * Prior to calling the initialization routine eth_port_init() the user * must set the following fields under mv643xx_private struct: * port_num User Ethernet port number. - * port_mac_addr[6] User defined port MAC address. * port_config User port configuration value. * port_config_extend User port config extend value. * port_sdma_config User port SDMA config value. @@ -1796,7 +1791,7 @@ static void eth_port_init(struct mv643xx_private *mp) * and ether_init_rx_desc_ring for Rx queues). * * INPUT: - * struct mv643xx_private *mp Ethernet port control struct + * dev - a pointer to the required interface * * OUTPUT: * Ethernet port is ready to receive and transmit. @@ -1804,8 +1799,9 @@ static void eth_port_init(struct mv643xx_private *mp) * RETURN: * None. */ -static void eth_port_start(struct mv643xx_private *mp) +static void eth_port_start(struct net_device *dev) { + struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; int tx_curr_desc, rx_curr_desc; @@ -1820,7 +1816,7 @@ static void eth_port_start(struct mv643xx_private *mp) (u32)((struct eth_rx_desc *)mp->rx_desc_dma + rx_curr_desc)); /* Add the assigned Ethernet address to the port's address table */ - eth_port_uc_addr_set(port_num, mp->port_mac_addr); + eth_port_uc_addr_set(port_num, dev->dev_addr); /* Assign port configuration and command. */ mv_write(MV643XX_ETH_PORT_CONFIG_REG(port_num), mp->port_config); diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index f769f9b626e..c83bcbdef4d 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -324,7 +324,6 @@ struct mv643xx_mib_counters { struct mv643xx_private { int port_num; /* User Ethernet port number */ - u8 port_mac_addr[6]; /* User defined port MAC address.*/ u32 port_config; /* User port configuration value*/ u32 port_config_extend; /* User port config extend value*/ u32 port_sdma_config; /* User port SDMA config value */ @@ -405,7 +404,7 @@ struct mv643xx_private { /* Port operation control routines */ static void eth_port_init(struct mv643xx_private *mp); static void eth_port_reset(unsigned int eth_port_num); -static void eth_port_start(struct mv643xx_private *mp); +static void eth_port_start(struct net_device *dev); /* Port MAC address routines */ static void eth_port_uc_addr_set(unsigned int eth_port_num, -- cgit v1.2.3 From cf4086c7725dc251551243c28325d446d9b1bf06 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 27 Jan 2006 01:07:48 -0700 Subject: [PATCH] mv643xx_eth: Merge unicast and multicast address filtering code Remove duplicated code by having unicast and multicast code use a common filter table function: eth_port_set_filter_table_entry(). Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 84 +++++------------------------------------------ drivers/net/mv643xx_eth.h | 4 --- 2 files changed, 9 insertions(+), 79 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index af9bbe649fc..4d5e3b8e757 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -1730,8 +1730,7 @@ static int ethernet_phy_get(unsigned int eth_port_num); static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr); /* Ethernet Port routines */ -static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble, - int option); +static void eth_port_set_filter_table_entry(int table, unsigned char entry); /* * eth_port_init - Initialize the Ethernet port driver @@ -1860,8 +1859,9 @@ static void eth_port_start(struct net_device *dev) * char * p_addr Address to be set * * OUTPUT: - * Set MAC address low and high registers. also calls eth_port_uc_addr() - * To set the unicast table with the proper information. + * Set MAC address low and high registers. also calls + * eth_port_set_filter_table_entry() to set the unicast + * table with the proper information. * * RETURN: * N/A. @@ -1872,6 +1872,7 @@ static void eth_port_uc_addr_set(unsigned int eth_port_num, { unsigned int mac_h; unsigned int mac_l; + int table; mac_l = (p_addr[4] << 8) | (p_addr[5]); mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) | @@ -1881,9 +1882,8 @@ static void eth_port_uc_addr_set(unsigned int eth_port_num, mv_write(MV643XX_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h); /* Accept frames of this address */ - eth_port_uc_addr(eth_port_num, p_addr[5], ACCEPT_MAC_ADDR); - - return; + table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(eth_port_num); + eth_port_set_filter_table_entry(table, p_addr[5] & 0x0f); } /* @@ -1921,72 +1921,6 @@ static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *p_addr) p_addr[5] = mac_l & 0xff; } -/* - * eth_port_uc_addr - This function Set the port unicast address table - * - * DESCRIPTION: - * This function locates the proper entry in the Unicast table for the - * specified MAC nibble and sets its properties according to function - * parameters. - * - * INPUT: - * unsigned int eth_port_num Port number. - * unsigned char uc_nibble Unicast MAC Address last nibble. - * int option 0 = Add, 1 = remove address. - * - * OUTPUT: - * This function add/removes MAC addresses from the port unicast address - * table. - * - * RETURN: - * true is output succeeded. - * false if option parameter is invalid. - * - */ -static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble, - int option) -{ - unsigned int unicast_reg; - unsigned int tbl_offset; - unsigned int reg_offset; - - /* Locate the Unicast table entry */ - uc_nibble = (0xf & uc_nibble); - tbl_offset = (uc_nibble / 4) * 4; /* Register offset from unicast table base */ - reg_offset = uc_nibble % 4; /* Entry offset within the above register */ - - switch (option) { - case REJECT_MAC_ADDR: - /* Clear accepts frame bit at given unicast DA table entry */ - unicast_reg = mv_read((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE - (eth_port_num) + tbl_offset)); - - unicast_reg &= (0x0E << (8 * reg_offset)); - - mv_write((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE - (eth_port_num) + tbl_offset), unicast_reg); - break; - - case ACCEPT_MAC_ADDR: - /* Set accepts frame bit at unicast DA filter table entry */ - unicast_reg = - mv_read((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE - (eth_port_num) + tbl_offset)); - - unicast_reg |= (0x01 << (8 * reg_offset)); - - mv_write((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE - (eth_port_num) + tbl_offset), unicast_reg); - - break; - - default: - return 0; - } - - return 1; -} - /* * The entries in each table are indexed by a hash of a packet's MAC * address. One bit in each entry determines whether the packet is @@ -2199,8 +2133,8 @@ static void eth_port_init_mac_tables(unsigned int eth_port_num) /* Clear DA filter unicast table (Ex_dFUT) */ for (table_index = 0; table_index <= 0xC; table_index += 4) - mv_write((MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE - (eth_port_num) + table_index), 0); + mv_write(MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE + (eth_port_num) + table_index, 0); for (table_index = 0; table_index <= 0xFC; table_index += 4) { /* Clear DA filter special multicast table (Ex_dFSMT) */ diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index c83bcbdef4d..ef83906f88e 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -89,10 +89,6 @@ * */ -/* MAC accepet/reject macros */ -#define ACCEPT_MAC_ADDR 0 -#define REJECT_MAC_ADDR 1 - /* Buffer offset from buffer pointer */ #define RX_BUF_OFFSET 0x2 -- cgit v1.2.3 From f98e36f1f7903a319f7f87f96490e88f691ea106 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 27 Jan 2006 01:09:18 -0700 Subject: [PATCH] mv643xx_eth: Rename mp->tx_ring_skbs to mp->tx_desc_count tx_ring_skbs is actually a count of tx descriptors currently in use. Since there may be multiple descriptors per skb, it is not the same as the number of skbs in the ring. Also change rx_ring_skbs to rx_desc_count to be consistent. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 51 ++++++++++++++++++++++++----------------------- drivers/net/mv643xx_eth.h | 8 ++++---- 2 files changed, 30 insertions(+), 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 4d5e3b8e757..73c766b3cd1 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -169,11 +169,11 @@ static void mv643xx_eth_rx_task(void *data) if (test_and_set_bit(0, &mp->rx_task_busy)) panic("%s: Error in test_set_bit / clear_bit", dev->name); - while (mp->rx_ring_skbs < (mp->rx_ring_size - 5)) { + while (mp->rx_desc_count < (mp->rx_ring_size - 5)) { skb = dev_alloc_skb(RX_SKB_SIZE + DMA_ALIGN); if (!skb) break; - mp->rx_ring_skbs++; + mp->rx_desc_count++; unaligned = (u32)skb->data & (DMA_ALIGN - 1); if (unaligned) skb_reserve(skb, DMA_ALIGN - unaligned); @@ -194,7 +194,7 @@ static void mv643xx_eth_rx_task(void *data) * If RX ring is empty of SKB, set a timer to try allocating * again in a later time . */ - if ((mp->rx_ring_skbs == 0) && (mp->rx_timer_flag == 0)) { + if ((mp->rx_desc_count == 0) && (mp->rx_timer_flag == 0)) { printk(KERN_INFO "%s: Rx ring is empty\n", dev->name); /* After 100mSec */ mp->timeout.expires = jiffies + (HZ / 10); @@ -394,7 +394,7 @@ static int mv643xx_eth_receive_queue(struct net_device *dev) #else while (eth_port_receive(mp, &pkt_info) == ETH_OK) { #endif - mp->rx_ring_skbs--; + mp->rx_desc_count--; received_packets++; /* Update statistics. Note byte count includes 4 byte CRC count */ @@ -494,7 +494,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, /* UDP change : We may need this */ if ((eth_int_cause_ext & 0x0000ffff) && (mv643xx_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) && - (mp->tx_ring_size > mp->tx_ring_skbs + MAX_DESCS_PER_SKB)) + (mp->tx_ring_size > mp->tx_desc_count + MAX_DESCS_PER_SKB)) netif_wake_queue(dev); #ifdef MV643XX_NAPI } else { @@ -778,7 +778,7 @@ static int mv643xx_eth_open(struct net_device *dev) } /* Allocate TX ring */ - mp->tx_ring_skbs = 0; + mp->tx_desc_count = 0; size = mp->tx_ring_size * sizeof(struct eth_tx_desc); mp->tx_desc_area_size = size; @@ -803,7 +803,7 @@ static int mv643xx_eth_open(struct net_device *dev) ether_init_tx_desc_ring(mp); /* Allocate RX ring */ - mp->rx_ring_skbs = 0; + mp->rx_desc_count = 0; size = mp->rx_ring_size * sizeof(struct eth_rx_desc); mp->rx_desc_area_size = size; @@ -880,17 +880,17 @@ static void mv643xx_eth_free_tx_rings(struct net_device *dev) mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 0x0000ff00); /* Free outstanding skb's on TX rings */ - for (curr = 0; mp->tx_ring_skbs && curr < mp->tx_ring_size; curr++) { + for (curr = 0; mp->tx_desc_count && curr < mp->tx_ring_size; curr++) { skb = mp->tx_skb[curr]; if (skb) { - mp->tx_ring_skbs -= skb_shinfo(skb)->nr_frags; + mp->tx_desc_count -= skb_shinfo(skb)->nr_frags; dev_kfree_skb(skb); - mp->tx_ring_skbs--; + mp->tx_desc_count--; } } - if (mp->tx_ring_skbs) + if (mp->tx_desc_count) printk("%s: Error on Tx descriptor free - could not free %d" - " descriptors\n", dev->name, mp->tx_ring_skbs); + " descriptors\n", dev->name, mp->tx_desc_count); /* Free TX ring */ if (mp->tx_sram_size) @@ -910,18 +910,18 @@ static void mv643xx_eth_free_rx_rings(struct net_device *dev) mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), 0x0000ff00); /* Free preallocated skb's on RX rings */ - for (curr = 0; mp->rx_ring_skbs && curr < mp->rx_ring_size; curr++) { + for (curr = 0; mp->rx_desc_count && curr < mp->rx_ring_size; curr++) { if (mp->rx_skb[curr]) { dev_kfree_skb(mp->rx_skb[curr]); - mp->rx_ring_skbs--; + mp->rx_desc_count--; } } - if (mp->rx_ring_skbs) + if (mp->rx_desc_count) printk(KERN_ERR "%s: Error in freeing Rx Ring. %d skb's still" " stuck in RX Ring - ignoring them\n", dev->name, - mp->rx_ring_skbs); + mp->rx_desc_count); /* Free RX ring */ if (mp->rx_sram_size) iounmap(mp->p_rx_desc_area); @@ -991,7 +991,8 @@ static void mv643xx_tx(struct net_device *dev) } if (netif_queue_stopped(dev) && - mp->tx_ring_size > mp->tx_ring_skbs + MAX_DESCS_PER_SKB) + mp->tx_ring_size > + mp->tx_desc_count + MAX_DESCS_PER_SKB) netif_wake_queue(dev); } @@ -1083,7 +1084,7 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) } /* This is a hard error, log it. */ - if ((mp->tx_ring_size - mp->tx_ring_skbs) <= + if ((mp->tx_ring_size - mp->tx_desc_count) <= (skb_shinfo(skb)->nr_frags + 1)) { netif_stop_queue(dev); printk(KERN_ERR @@ -1260,7 +1261,7 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Check if TX queue can handle another skb. If not, then * signal higher layers to stop requesting TX */ - if (mp->tx_ring_size <= (mp->tx_ring_skbs + MAX_DESCS_PER_SKB)) + if (mp->tx_ring_size <= (mp->tx_desc_count + MAX_DESCS_PER_SKB)) /* * Stop getting skb's from upper layers. * Getting skb's from upper layers will be enabled again after @@ -2563,8 +2564,8 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, return ETH_ERROR; } - mp->tx_ring_skbs++; - BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size); + mp->tx_desc_count++; + BUG_ON(mp->tx_desc_count > mp->tx_ring_size); /* Get the Tx Desc ring indexes */ tx_desc_curr = mp->tx_curr_desc_q; @@ -2632,8 +2633,8 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, if (mp->tx_resource_err) return ETH_QUEUE_FULL; - mp->tx_ring_skbs++; - BUG_ON(mp->tx_ring_skbs > mp->tx_ring_size); + mp->tx_desc_count++; + BUG_ON(mp->tx_desc_count > mp->tx_ring_size); /* Get the Tx Desc ring indexes */ tx_desc_curr = mp->tx_curr_desc_q; @@ -2747,8 +2748,8 @@ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, /* Any Tx return cancels the Tx resource error status */ mp->tx_resource_err = 0; - BUG_ON(mp->tx_ring_skbs == 0); - mp->tx_ring_skbs--; + BUG_ON(mp->tx_desc_count == 0); + mp->tx_desc_count--; out: spin_unlock_irqrestore(&mp->lock, flags); diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index ef83906f88e..345f970d122 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -371,12 +371,12 @@ struct mv643xx_private { spinlock_t lock; /* Size of Tx Ring per queue */ unsigned int tx_ring_size; - /* Ammont of SKBs outstanding on Tx queue */ - unsigned int tx_ring_skbs; + /* Number of tx descriptors in use */ + unsigned int tx_desc_count; /* Size of Rx Ring per queue */ unsigned int rx_ring_size; - /* Ammount of SKBs allocated to Rx Ring per queue */ - unsigned int rx_ring_skbs; + /* Number of rx descriptors in use */ + unsigned int rx_desc_count; /* * rx_task used to fill RX ring out of bottom half context -- cgit v1.2.3 From 9f8dd319459bb5ab9efcc1c345bed7895cc41768 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 27 Jan 2006 01:10:47 -0700 Subject: [PATCH] mv643xx_eth: Make port queue enable/disable code consistent Add and use the following functions: mv643xx_eth_port_enable_tx() mv643xx_eth_port_enable_rx() mv643xx_eth_port_disable_tx() mv643xx_eth_port_disable_rx() so that ports are enabled/disabled consistently. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 133 +++++++++++++++++++++++++++------------------- 1 file changed, 79 insertions(+), 54 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 73c766b3cd1..2daa9b97d2c 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -83,6 +83,12 @@ static int eth_port_link_is_up(unsigned int eth_port_num); static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *MacAddr); static void eth_port_set_multicast_list(struct net_device *); +static void mv643xx_eth_port_enable_tx(unsigned int port_num, + unsigned int channels); +static void mv643xx_eth_port_enable_rx(unsigned int port_num, + unsigned int channels); +static unsigned int mv643xx_eth_port_disable_tx(unsigned int port_num); +static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num); static int mv643xx_eth_open(struct net_device *); static int mv643xx_eth_stop(struct net_device *); static int mv643xx_eth_change_mtu(struct net_device *, int); @@ -535,8 +541,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, netif_carrier_on(dev); netif_wake_queue(dev); /* Start TX queue */ - mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG - (port_num), 1); + mv643xx_eth_port_enable_tx(port_num, mp->port_tx_queue_command); } else { netif_carrier_off(dev); netif_stop_queue(dev); @@ -668,8 +673,8 @@ static void ether_init_rx_desc_ring(struct mv643xx_private *mp) mp->rx_desc_area_size = rx_desc_num * sizeof(struct eth_rx_desc); - /* Add the queue to the list of RX queues of this port */ - mp->port_rx_queue_command |= 1; + /* Enable queue 0 for this port */ + mp->port_rx_queue_command = 1; } /* @@ -715,8 +720,8 @@ static void ether_init_tx_desc_ring(struct mv643xx_private *mp) mp->tx_desc_area_size = tx_desc_num * sizeof(struct eth_tx_desc); - /* Add the queue to the list of Tx queues of this port */ - mp->port_tx_queue_command |= 1; + /* Enable queue 0 for this port */ + mp->port_tx_queue_command = 1; } /* @@ -747,9 +752,6 @@ static int mv643xx_eth_open(struct net_device *dev) return -EAGAIN; } - /* Stop RX Queues */ - mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), 0x0000ff00); - eth_port_init(mp); INIT_WORK(&mp->rx_task, (void (*)(void *))mv643xx_eth_rx_task, dev); @@ -877,7 +879,7 @@ static void mv643xx_eth_free_tx_rings(struct net_device *dev) struct sk_buff *skb; /* Stop Tx Queues */ - mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), 0x0000ff00); + mv643xx_eth_port_disable_tx(port_num); /* Free outstanding skb's on TX rings */ for (curr = 0; mp->tx_desc_count && curr < mp->tx_ring_size; curr++) { @@ -907,7 +909,7 @@ static void mv643xx_eth_free_rx_rings(struct net_device *dev) int curr; /* Stop RX Queues */ - mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), 0x0000ff00); + mv643xx_eth_port_disable_rx(port_num); /* Free preallocated skb's on RX rings */ for (curr = 0; mp->rx_desc_count && curr < mp->rx_ring_size; curr++) { @@ -1719,13 +1721,6 @@ MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX"); * return_info Tx/Rx user resource return information. */ -/* defines */ -/* SDMA command macros */ -#define ETH_ENABLE_TX_QUEUE(eth_port) \ - mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(eth_port), 1) - -/* locals */ - /* PHY routines */ static int ethernet_phy_get(unsigned int eth_port_num); static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr); @@ -1759,9 +1754,6 @@ static void eth_port_set_filter_table_entry(int table, unsigned char entry); */ static void eth_port_init(struct mv643xx_private *mp) { - mp->port_rx_queue_command = 0; - mp->port_tx_queue_command = 0; - mp->rx_resource_err = 0; mp->tx_resource_err = 0; @@ -1842,8 +1834,7 @@ static void eth_port_start(struct net_device *dev) mp->port_sdma_config); /* Enable port Rx. */ - mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), - mp->port_rx_queue_command); + mv643xx_eth_port_enable_rx(port_num, mp->port_rx_queue_command); /* Disable port bandwidth limits by clearing MTU register */ mv_write(MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port_num), 0); @@ -2320,6 +2311,67 @@ static void ethernet_phy_reset(unsigned int eth_port_num) eth_port_write_smi_reg(eth_port_num, 0, phy_reg_data); } +static void mv643xx_eth_port_enable_tx(unsigned int port_num, + unsigned int channels) +{ + mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), channels); +} + +static void mv643xx_eth_port_enable_rx(unsigned int port_num, + unsigned int channels) +{ + mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), channels); +} + +static unsigned int mv643xx_eth_port_disable_tx(unsigned int port_num) +{ + u32 channels; + + /* Stop Tx port activity. Check port Tx activity. */ + channels = mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num)) + & 0xFF; + if (channels) { + /* Issue stop command for active channels only */ + mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), + (channels << 8)); + + /* Wait for all Tx activity to terminate. */ + /* Check port cause register that all Tx queues are stopped */ + while (mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num)) + & 0xFF) + udelay(PHY_WAIT_MICRO_SECONDS); + + /* Wait for Tx FIFO to empty */ + while (mv_read(MV643XX_ETH_PORT_STATUS_REG(port_num)) & + ETH_PORT_TX_FIFO_EMPTY) + udelay(PHY_WAIT_MICRO_SECONDS); + } + + return channels; +} + +static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num) +{ + u32 channels; + + /* Stop Rx port activity. Check port Rx activity. */ + channels = mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num) + & 0xFF); + if (channels) { + /* Issue stop command for active channels only */ + mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), + (channels << 8)); + + /* Wait for all Rx activity to terminate. */ + /* Check port cause register that all Rx queues are stopped */ + while (mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num)) + & 0xFF) + udelay(PHY_WAIT_MICRO_SECONDS); + } + + return channels; +} + /* * eth_port_reset - Reset Ethernet port * @@ -2342,35 +2394,8 @@ static void eth_port_reset(unsigned int port_num) { unsigned int reg_data; - /* Stop Tx port activity. Check port Tx activity. */ - reg_data = mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num)); - - if (reg_data & 0xFF) { - /* Issue stop command for active channels only */ - mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), - (reg_data << 8)); - - /* Wait for all Tx activity to terminate. */ - /* Check port cause register that all Tx queues are stopped */ - while (mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num)) - & 0xFF) - udelay(10); - } - - /* Stop Rx port activity. Check port Rx activity. */ - reg_data = mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num)); - - if (reg_data & 0xFF) { - /* Issue stop command for active channels only */ - mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), - (reg_data << 8)); - - /* Wait for all Rx activity to terminate. */ - /* Check port cause register that all Rx queues are stopped */ - while (mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num)) - & 0xFF) - udelay(10); - } + mv643xx_eth_port_disable_tx(port_num); + mv643xx_eth_port_disable_rx(port_num); /* Clear all MIB counters */ eth_clear_mib_counters(port_num); @@ -2599,7 +2624,7 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, first_descriptor->cmd_sts = mp->tx_first_command; wmb(); - ETH_ENABLE_TX_QUEUE(mp->port_num); + mv643xx_eth_port_enable_tx(mp->port_num, mp->port_tx_queue_command); /* * Finish Tx packet. Update first desc in case of Tx resource @@ -2652,7 +2677,7 @@ static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, ETH_BUFFER_OWNED_BY_DMA | ETH_TX_ENABLE_INTERRUPT; wmb(); - ETH_ENABLE_TX_QUEUE(mp->port_num); + mv643xx_eth_port_enable_tx(mp->port_num, mp->port_tx_queue_command); /* Finish Tx packet. Update first desc in case of Tx resource error */ tx_desc_curr = (tx_desc_curr + 1) % mp->tx_ring_size; -- cgit v1.2.3 From c28a4f8947f1b08996502967e348dc88363749a7 Mon Sep 17 00:00:00 2001 From: James Chapman Date: Fri, 27 Jan 2006 01:13:15 -0700 Subject: [PATCH] mv643xx_eth: use MII library for PHY management Modify link up/down handling to use the functions from the MII library. Note that I track link state using the MII PHY registers rather than the mv643xx chip's link state registers because I think it's cleaner to use the MII library code rather than writing local driver support code. It is also useful to make the actual MII registers available to the user with maskable kernel printk messages so the MII registers are being read anyway Signed-off-by: James Chapman Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 64 ++++++++++++++++++++++++++++++----------------- drivers/net/mv643xx_eth.h | 2 ++ 2 files changed, 43 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 2daa9b97d2c..bca7257c707 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -79,7 +79,6 @@ #define PHY_WAIT_MICRO_SECONDS 10 /* Static function declarations */ -static int eth_port_link_is_up(unsigned int eth_port_num); static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *MacAddr); static void eth_port_set_multicast_list(struct net_device *); @@ -97,8 +96,11 @@ static void eth_port_init_mac_tables(unsigned int eth_port_num); #ifdef MV643XX_NAPI static int mv643xx_poll(struct net_device *dev, int *budget); #endif +static int ethernet_phy_get(unsigned int eth_port_num); static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr); static int ethernet_phy_detect(unsigned int eth_port_num); +static int mv643xx_mdio_read(struct net_device *dev, int phy_id, int location); +static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, int val); static struct ethtool_ops mv643xx_ethtool_ops; static char mv643xx_driver_name[] = "mv643xx_eth"; @@ -537,14 +539,17 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, } /* PHY status changed */ if (eth_int_cause_ext & (BIT16 | BIT20)) { - if (eth_port_link_is_up(port_num)) { - netif_carrier_on(dev); - netif_wake_queue(dev); - /* Start TX queue */ - mv643xx_eth_port_enable_tx(port_num, mp->port_tx_queue_command); - } else { - netif_carrier_off(dev); + if (mii_link_ok(&mp->mii)) { + if (!netif_carrier_ok(dev)) { + netif_carrier_on(dev); + netif_wake_queue(dev); + /* Start TX queue */ + mv643xx_eth_port_enable_tx(port_num, + mp->port_tx_queue_command); + } + } else if (netif_carrier_ok(dev)) { netif_stop_queue(dev); + netif_carrier_off(dev); } } @@ -1434,6 +1439,14 @@ static int mv643xx_eth_probe(struct platform_device *pdev) } } + /* Hook up MII support for ethtool */ + mp->mii.dev = dev; + mp->mii.mdio_read = mv643xx_mdio_read; + mp->mii.mdio_write = mv643xx_mdio_write; + mp->mii.phy_id = ethernet_phy_get(port_num); + mp->mii.phy_id_mask = 0x3f; + mp->mii.reg_num_mask = 0x1f; + err = ethernet_phy_detect(port_num); if (err) { pr_debug("MV643xx ethernet port %d: " @@ -1442,6 +1455,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev) return err; } + mp->mii.supports_gmii = mii_check_gmii_support(&mp->mii); + err = register_netdev(dev); if (err) goto out; @@ -2416,21 +2431,6 @@ static int eth_port_autoneg_supported(unsigned int eth_port_num) return phy_reg_data0 & 0x1000; } -static int eth_port_link_is_up(unsigned int eth_port_num) -{ - unsigned int phy_reg_data1; - - eth_port_read_smi_reg(eth_port_num, 1, &phy_reg_data1); - - if (eth_port_autoneg_supported(eth_port_num)) { - if (phy_reg_data1 & 0x20) /* auto-neg complete */ - return 1; - } else if (phy_reg_data1 & 0x4) /* link up */ - return 1; - - return 0; -} - /* * eth_port_read_smi_reg - Read PHY registers * @@ -2535,6 +2535,24 @@ out: spin_unlock_irqrestore(&mv643xx_eth_phy_lock, flags); } +/* + * Wrappers for MII support library. + */ +static int mv643xx_mdio_read(struct net_device *dev, int phy_id, int location) +{ + int val; + struct mv643xx_private *mp = netdev_priv(dev); + + eth_port_read_smi_reg(mp->port_num, location, &val); + return val; +} + +static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, int val) +{ + struct mv643xx_private *mp = netdev_priv(dev); + eth_port_write_smi_reg(mp->port_num, location, val); +} + /* * eth_port_send - Send an Ethernet packet * diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index 345f970d122..f2e5da79dde 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -393,6 +394,7 @@ struct mv643xx_private { u32 rx_int_coal; u32 tx_int_coal; + struct mii_if_info mii; }; /* ethernet.h API list */ -- cgit v1.2.3 From d0412d967032b9e147bcbacc9ff0c0342636cf2d Mon Sep 17 00:00:00 2001 From: James Chapman Date: Fri, 27 Jan 2006 01:15:30 -0700 Subject: [PATCH] mv643xx_eth: use MII library for ethtool functions Use the common ethtool support functions of the MII library. Add generic MII ioctl handler. Add PHY parameter speed/duplex/negotiation initialization and modification. Signed-off-by: James Chapman Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 351 +++++++++++++++++++++++++++------------------- 1 file changed, 210 insertions(+), 141 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index bca7257c707..ff2b613a743 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -101,6 +101,7 @@ static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr); static int ethernet_phy_detect(unsigned int eth_port_num); static int mv643xx_mdio_read(struct net_device *dev, int phy_id, int location); static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, int val); +static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); static struct ethtool_ops mv643xx_ethtool_ops; static char mv643xx_driver_name[] = "mv643xx_eth"; @@ -457,6 +458,56 @@ static int mv643xx_eth_receive_queue(struct net_device *dev) return received_packets; } +/* Set the mv643xx port configuration register for the speed/duplex mode. */ +static void mv643xx_eth_update_pscr(struct net_device *dev, + struct ethtool_cmd *ecmd) +{ + struct mv643xx_private *mp = netdev_priv(dev); + int port_num = mp->port_num; + u32 o_pscr, n_pscr; + unsigned int channels; + + o_pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); + n_pscr = o_pscr; + + /* clear speed, duplex and rx buffer size fields */ + n_pscr &= ~(MV643XX_ETH_SET_MII_SPEED_TO_100 | + MV643XX_ETH_SET_GMII_SPEED_TO_1000 | + MV643XX_ETH_SET_FULL_DUPLEX_MODE | + MV643XX_ETH_MAX_RX_PACKET_MASK); + + if (ecmd->duplex == DUPLEX_FULL) + n_pscr |= MV643XX_ETH_SET_FULL_DUPLEX_MODE; + + if (ecmd->speed == SPEED_1000) + n_pscr |= MV643XX_ETH_SET_GMII_SPEED_TO_1000 | + MV643XX_ETH_MAX_RX_PACKET_9700BYTE; + else { + if (ecmd->speed == SPEED_100) + n_pscr |= MV643XX_ETH_SET_MII_SPEED_TO_100; + n_pscr |= MV643XX_ETH_MAX_RX_PACKET_1522BYTE; + } + + if (n_pscr != o_pscr) { + if ((o_pscr & MV643XX_ETH_SERIAL_PORT_ENABLE) == 0) + mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), + n_pscr); + else { + channels = mv643xx_eth_port_disable_tx(port_num); + + o_pscr &= ~MV643XX_ETH_SERIAL_PORT_ENABLE; + mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), + o_pscr); + mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), + n_pscr); + mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), + n_pscr); + if (channels) + mv643xx_eth_port_enable_tx(port_num, channels); + } + } +} + /* * mv643xx_eth_int_handler * @@ -539,13 +590,19 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, } /* PHY status changed */ if (eth_int_cause_ext & (BIT16 | BIT20)) { + struct ethtool_cmd cmd; + if (mii_link_ok(&mp->mii)) { + mii_ethtool_gset(&mp->mii, &cmd); + mv643xx_eth_update_pscr(dev, &cmd); if (!netif_carrier_ok(dev)) { netif_carrier_on(dev); - netif_wake_queue(dev); - /* Start TX queue */ - mv643xx_eth_port_enable_tx(port_num, - mp->port_tx_queue_command); + if (mp->tx_ring_size > mp->tx_desc_count + + MAX_DESCS_PER_SKB) { + netif_wake_queue(dev); + /* Start TX queue */ + mv643xx_eth_port_enable_tx(port_num, mp->port_tx_queue_command); + } } } else if (netif_carrier_ok(dev)) { netif_stop_queue(dev); @@ -729,6 +786,34 @@ static void ether_init_tx_desc_ring(struct mv643xx_private *mp) mp->port_tx_queue_command = 1; } +static int mv643xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct mv643xx_private *mp = netdev_priv(dev); + int err; + + spin_lock_irq(&mp->lock); + err = mii_ethtool_sset(&mp->mii, cmd); + spin_unlock_irq(&mp->lock); + + return err; +} + +static int mv643xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct mv643xx_private *mp = netdev_priv(dev); + int err; + + spin_lock_irq(&mp->lock); + err = mii_ethtool_gset(&mp->mii, cmd); + spin_unlock_irq(&mp->lock); + + /* The PHY may support 1000baseT_Half, but the mv643xx does not */ + cmd->supported &= ~SUPPORTED_1000baseT_Half; + cmd->advertising &= ~ADVERTISED_1000baseT_Half; + + return err; +} + /* * mv643xx_eth_open * @@ -842,6 +927,10 @@ static int mv643xx_eth_open(struct net_device *dev) mv643xx_eth_rx_task(dev); /* Fill RX ring with skb's */ + /* Clear any pending ethernet port interrupts */ + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); + eth_port_start(dev); /* Interrupt Coalescing */ @@ -854,16 +943,13 @@ static int mv643xx_eth_open(struct net_device *dev) mp->tx_int_coal = eth_port_set_tx_coal(port_num, 133000000, MV643XX_TX_COAL); - /* Clear any pending ethernet port interrupts */ - mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); - mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); - /* Unmask phy and link status changes interrupts */ mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), INT_UNMASK_ALL_EXT); /* Unmask RX buffer and TX end interrupt */ mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_UNMASK_ALL); + return 0; out_free_tx_skb: @@ -1318,6 +1404,35 @@ static void mv643xx_netpoll(struct net_device *netdev) } #endif +static void mv643xx_init_ethtool_cmd(struct net_device *dev, int phy_address, + int speed, int duplex, + struct ethtool_cmd *cmd) +{ + struct mv643xx_private *mp = netdev_priv(dev); + + memset(cmd, 0, sizeof(*cmd)); + + cmd->port = PORT_MII; + cmd->transceiver = XCVR_INTERNAL; + cmd->phy_address = phy_address; + + if (speed == 0) { + cmd->autoneg = AUTONEG_ENABLE; + /* mii lib checks, but doesn't use speed on AUTONEG_ENABLE */ + cmd->speed = SPEED_100; + cmd->advertising = ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full; + if (mp->mii.supports_gmii) + cmd->advertising |= ADVERTISED_1000baseT_Full; + } else { + cmd->autoneg = AUTONEG_DISABLE; + cmd->speed = speed; + cmd->duplex = duplex; + } +} + /*/ * mv643xx_eth_probe * @@ -1338,6 +1453,10 @@ static int mv643xx_eth_probe(struct platform_device *pdev) u8 *p; struct resource *res; int err; + struct ethtool_cmd cmd; + u32 pscr; + int duplex; + int speed; dev = alloc_etherdev(sizeof(struct mv643xx_private)); if (!dev) @@ -1375,6 +1494,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) dev->tx_queue_len = mp->tx_ring_size; dev->base_addr = 0; dev->change_mtu = mv643xx_eth_change_mtu; + dev->do_ioctl = mv643xx_eth_do_ioctl; SET_ETHTOOL_OPS(dev, &mv643xx_ethtool_ops); #ifdef MV643XX_CHECKSUM_OFFLOAD_TX @@ -1452,10 +1572,35 @@ static int mv643xx_eth_probe(struct platform_device *pdev) pr_debug("MV643xx ethernet port %d: " "No PHY detected at addr %d\n", port_num, ethernet_phy_get(port_num)); - return err; + goto out; } + pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); + pscr &= ~MV643XX_ETH_SERIAL_PORT_ENABLE; + mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); + pscr = mp->port_serial_control; + mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); + + if (!(pscr & MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX) && + !(pscr & MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII)) + speed = 0; + else if (pscr & MV643XX_ETH_PORT_STATUS_GMII_1000) + speed = SPEED_1000; + else if (pscr & MV643XX_ETH_PORT_STATUS_MII_100) + speed = SPEED_100; + else + speed = SPEED_10; + + if (pscr & MV643XX_ETH_PORT_STATUS_FULL_DUPLEX) + duplex = DUPLEX_FULL; + else + duplex = DUPLEX_HALF; + + ethernet_phy_reset(mp->port_num); mp->mii.supports_gmii = mii_check_gmii_support(&mp->mii); + mv643xx_init_ethtool_cmd(dev, mp->mii.phy_id, speed, duplex, &cmd); + mv643xx_eth_update_pscr(dev, &cmd); + mv643xx_set_settings(dev, &cmd); err = register_netdev(dev); if (err) @@ -1775,8 +1920,6 @@ static void eth_port_init(struct mv643xx_private *mp) eth_port_reset(mp->port_num); eth_port_init_mac_tables(mp->port_num); - - ethernet_phy_reset(mp->port_num); } /* @@ -1811,6 +1954,8 @@ static void eth_port_start(struct net_device *dev) struct mv643xx_private *mp = netdev_priv(dev); unsigned int port_num = mp->port_num; int tx_curr_desc, rx_curr_desc; + u32 pscr; + struct ethtool_cmd ethtool_cmd; /* Assignment of Tx CTRP of given queue */ tx_curr_desc = mp->tx_curr_desc_q; @@ -1828,31 +1973,35 @@ static void eth_port_start(struct net_device *dev) /* Assign port configuration and command. */ mv_write(MV643XX_ETH_PORT_CONFIG_REG(port_num), mp->port_config); - mv_write(MV643XX_ETH_PORT_CONFIG_EXTEND_REG(port_num), - mp->port_config_extend); + pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); + pscr &= ~MV643XX_ETH_SERIAL_PORT_ENABLE; + mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); + pscr &= ~MV643XX_ETH_FORCE_LINK_PASS; + pscr |= MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | + MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII | + MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX | + MV643XX_ETH_DO_NOT_FORCE_LINK_FAIL | + MV643XX_ETH_SERIAL_PORT_CONTROL_RESERVED; - /* Increase the Rx side buffer size if supporting GigE */ - if (mp->port_serial_control & MV643XX_ETH_SET_GMII_SPEED_TO_1000) - mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), - (mp->port_serial_control & 0xfff1ffff) | (0x5 << 17)); - else - mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), - mp->port_serial_control); + mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); - mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), - mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)) | - MV643XX_ETH_SERIAL_PORT_ENABLE); + pscr |= MV643XX_ETH_SERIAL_PORT_ENABLE; + mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); /* Assign port SDMA configuration */ - mv_write(MV643XX_ETH_SDMA_CONFIG_REG(port_num), - mp->port_sdma_config); + mv_write(MV643XX_ETH_SDMA_CONFIG_REG(port_num), mp->port_sdma_config); /* Enable port Rx. */ mv643xx_eth_port_enable_rx(port_num, mp->port_rx_queue_command); /* Disable port bandwidth limits by clearing MTU register */ mv_write(MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port_num), 0); + + /* save phy settings across reset */ + mv643xx_get_settings(dev, ðtool_cmd); + ethernet_phy_reset(mp->port_num); + mv643xx_set_settings(dev, ðtool_cmd); } /* @@ -2324,6 +2473,12 @@ static void ethernet_phy_reset(unsigned int eth_port_num) eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data); phy_reg_data |= 0x8000; /* Set bit 15 to reset the PHY */ eth_port_write_smi_reg(eth_port_num, 0, phy_reg_data); + + /* wait for PHY to come out of reset */ + do { + udelay(1); + eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data); + } while (phy_reg_data & 0x8000); } static void mv643xx_eth_port_enable_tx(unsigned int port_num, @@ -2417,20 +2572,13 @@ static void eth_port_reset(unsigned int port_num) /* Reset the Enable bit in the Configuration Register */ reg_data = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); - reg_data &= ~MV643XX_ETH_SERIAL_PORT_ENABLE; + reg_data &= ~(MV643XX_ETH_SERIAL_PORT_ENABLE | + MV643XX_ETH_DO_NOT_FORCE_LINK_FAIL | + MV643XX_ETH_FORCE_LINK_PASS); mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), reg_data); } -static int eth_port_autoneg_supported(unsigned int eth_port_num) -{ - unsigned int phy_reg_data0; - - eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data0); - - return phy_reg_data0 & 0x1000; -} - /* * eth_port_read_smi_reg - Read PHY registers * @@ -2989,111 +3137,6 @@ static const struct mv643xx_stats mv643xx_gstrings_stats[] = { #define MV643XX_STATS_LEN \ sizeof(mv643xx_gstrings_stats) / sizeof(struct mv643xx_stats) -static int -mv643xx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) -{ - struct mv643xx_private *mp = netdev->priv; - int port_num = mp->port_num; - int autoneg = eth_port_autoneg_supported(port_num); - int mode_10_bit; - int auto_duplex; - int half_duplex = 0; - int full_duplex = 0; - int auto_speed; - int speed_10 = 0; - int speed_100 = 0; - int speed_1000 = 0; - - u32 pcs = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); - u32 psr = mv_read(MV643XX_ETH_PORT_STATUS_REG(port_num)); - - mode_10_bit = psr & MV643XX_ETH_PORT_STATUS_MODE_10_BIT; - - if (mode_10_bit) { - ecmd->supported = SUPPORTED_10baseT_Half; - } else { - ecmd->supported = (SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_1000baseT_Full | - (autoneg ? SUPPORTED_Autoneg : 0) | - SUPPORTED_TP); - - auto_duplex = !(pcs & MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX); - auto_speed = !(pcs & MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII); - - ecmd->advertising = ADVERTISED_TP; - - if (autoneg) { - ecmd->advertising |= ADVERTISED_Autoneg; - - if (auto_duplex) { - half_duplex = 1; - full_duplex = 1; - } else { - if (pcs & MV643XX_ETH_SET_FULL_DUPLEX_MODE) - full_duplex = 1; - else - half_duplex = 1; - } - - if (auto_speed) { - speed_10 = 1; - speed_100 = 1; - speed_1000 = 1; - } else { - if (pcs & MV643XX_ETH_SET_GMII_SPEED_TO_1000) - speed_1000 = 1; - else if (pcs & MV643XX_ETH_SET_MII_SPEED_TO_100) - speed_100 = 1; - else - speed_10 = 1; - } - - if (speed_10 & half_duplex) - ecmd->advertising |= ADVERTISED_10baseT_Half; - if (speed_10 & full_duplex) - ecmd->advertising |= ADVERTISED_10baseT_Full; - if (speed_100 & half_duplex) - ecmd->advertising |= ADVERTISED_100baseT_Half; - if (speed_100 & full_duplex) - ecmd->advertising |= ADVERTISED_100baseT_Full; - if (speed_1000) - ecmd->advertising |= ADVERTISED_1000baseT_Full; - } - } - - ecmd->port = PORT_TP; - ecmd->phy_address = ethernet_phy_get(port_num); - - ecmd->transceiver = XCVR_EXTERNAL; - - if (netif_carrier_ok(netdev)) { - if (mode_10_bit) - ecmd->speed = SPEED_10; - else { - if (psr & MV643XX_ETH_PORT_STATUS_GMII_1000) - ecmd->speed = SPEED_1000; - else if (psr & MV643XX_ETH_PORT_STATUS_MII_100) - ecmd->speed = SPEED_100; - else - ecmd->speed = SPEED_10; - } - - if (psr & MV643XX_ETH_PORT_STATUS_FULL_DUPLEX) - ecmd->duplex = DUPLEX_FULL; - else - ecmd->duplex = DUPLEX_HALF; - } else { - ecmd->speed = -1; - ecmd->duplex = -1; - } - - ecmd->autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE; - return 0; -} - static void mv643xx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { @@ -3140,15 +3183,41 @@ static void mv643xx_get_strings(struct net_device *netdev, uint32_t stringset, } } +static u32 mv643xx_eth_get_link(struct net_device *dev) +{ + struct mv643xx_private *mp = netdev_priv(dev); + + return mii_link_ok(&mp->mii); +} + +static int mv643xx_eth_nway_restart(struct net_device *dev) +{ + struct mv643xx_private *mp = netdev_priv(dev); + + return mii_nway_restart(&mp->mii); +} + +static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct mv643xx_private *mp = netdev_priv(dev); + + return generic_mii_ioctl(&mp->mii, if_mii(ifr), cmd, NULL); +} + static struct ethtool_ops mv643xx_ethtool_ops = { .get_settings = mv643xx_get_settings, + .set_settings = mv643xx_set_settings, .get_drvinfo = mv643xx_get_drvinfo, - .get_link = ethtool_op_get_link, + .get_link = mv643xx_eth_get_link, .get_sg = ethtool_op_get_sg, .set_sg = ethtool_op_set_sg, .get_strings = mv643xx_get_strings, .get_stats_count = mv643xx_get_stats_count, .get_ethtool_stats = mv643xx_get_ethtool_stats, + .get_strings = mv643xx_get_strings, + .get_stats_count = mv643xx_get_stats_count, + .get_ethtool_stats = mv643xx_get_ethtool_stats, + .nway_reset = mv643xx_eth_nway_restart, }; /************* End ethtool support *************************/ -- cgit v1.2.3 From 01999873a455fe9104e91820c72849e608239928 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 27 Jan 2006 01:18:01 -0700 Subject: [PATCH] mv643xx_eth: Clean up platform_data configuration We shouldn't expose the hardware register contents in platform_data. The only things we allow the user to configure are autoneg, speed, and duplex. Add specific platform_data fields for these values and remove the registers configs. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 71 ++++++++++++++--------------------------------- drivers/net/mv643xx_eth.h | 4 --- 2 files changed, 21 insertions(+), 54 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index ff2b613a743..df572018595 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -266,13 +266,14 @@ static void mv643xx_eth_update_mac_address(struct net_device *dev) static void mv643xx_eth_set_rx_mode(struct net_device *dev) { struct mv643xx_private *mp = netdev_priv(dev); + u32 config_reg; + config_reg = mv_read(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num)); if (dev->flags & IFF_PROMISC) - mp->port_config |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE; + config_reg |= (u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE; else - mp->port_config &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE; - - mv_write(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num), mp->port_config); + config_reg &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE; + mv_write(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num), config_reg); eth_port_set_multicast_list(dev); } @@ -1454,9 +1455,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev) struct resource *res; int err; struct ethtool_cmd cmd; - u32 pscr; - int duplex; - int speed; + int duplex = DUPLEX_HALF; + int speed = 0; /* default to auto-negotiation */ dev = alloc_etherdev(sizeof(struct mv643xx_private)); if (!dev) @@ -1515,33 +1515,17 @@ static int mv643xx_eth_probe(struct platform_device *pdev) /* set default config values */ eth_port_uc_addr_get(dev, dev->dev_addr); - mp->port_config = MV643XX_ETH_PORT_CONFIG_DEFAULT_VALUE; - mp->port_config_extend = MV643XX_ETH_PORT_CONFIG_EXTEND_DEFAULT_VALUE; - mp->port_sdma_config = MV643XX_ETH_PORT_SDMA_CONFIG_DEFAULT_VALUE; - mp->port_serial_control = MV643XX_ETH_PORT_SERIAL_CONTROL_DEFAULT_VALUE; mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE; mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE; pd = pdev->dev.platform_data; if (pd) { - if (pd->mac_addr != NULL) + if (pd->mac_addr) memcpy(dev->dev_addr, pd->mac_addr, 6); if (pd->phy_addr || pd->force_phy_addr) ethernet_phy_set(port_num, pd->phy_addr); - if (pd->port_config || pd->force_port_config) - mp->port_config = pd->port_config; - - if (pd->port_config_extend || pd->force_port_config_extend) - mp->port_config_extend = pd->port_config_extend; - - if (pd->port_sdma_config || pd->force_port_sdma_config) - mp->port_sdma_config = pd->port_sdma_config; - - if (pd->port_serial_control || pd->force_port_serial_control) - mp->port_serial_control = pd->port_serial_control; - if (pd->rx_queue_size) mp->rx_ring_size = pd->rx_queue_size; @@ -1557,6 +1541,9 @@ static int mv643xx_eth_probe(struct platform_device *pdev) mp->rx_sram_size = pd->rx_sram_size; mp->rx_sram_addr = pd->rx_sram_addr; } + + duplex = pd->duplex; + speed = pd->speed; } /* Hook up MII support for ethtool */ @@ -1575,28 +1562,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) goto out; } - pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); - pscr &= ~MV643XX_ETH_SERIAL_PORT_ENABLE; - mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); - pscr = mp->port_serial_control; - mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); - - if (!(pscr & MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX) && - !(pscr & MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII)) - speed = 0; - else if (pscr & MV643XX_ETH_PORT_STATUS_GMII_1000) - speed = SPEED_1000; - else if (pscr & MV643XX_ETH_PORT_STATUS_MII_100) - speed = SPEED_100; - else - speed = SPEED_10; - - if (pscr & MV643XX_ETH_PORT_STATUS_FULL_DUPLEX) - duplex = DUPLEX_FULL; - else - duplex = DUPLEX_HALF; - - ethernet_phy_reset(mp->port_num); + ethernet_phy_reset(port_num); mp->mii.supports_gmii = mii_check_gmii_support(&mp->mii); mv643xx_init_ethtool_cmd(dev, mp->mii.phy_id, speed, duplex, &cmd); mv643xx_eth_update_pscr(dev, &cmd); @@ -1971,13 +1937,17 @@ static void eth_port_start(struct net_device *dev) eth_port_uc_addr_set(port_num, dev->dev_addr); /* Assign port configuration and command. */ - mv_write(MV643XX_ETH_PORT_CONFIG_REG(port_num), mp->port_config); + mv_write(MV643XX_ETH_PORT_CONFIG_REG(port_num), + MV643XX_ETH_PORT_CONFIG_DEFAULT_VALUE); + + mv_write(MV643XX_ETH_PORT_CONFIG_EXTEND_REG(port_num), + MV643XX_ETH_PORT_CONFIG_EXTEND_DEFAULT_VALUE); pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); - pscr &= ~MV643XX_ETH_SERIAL_PORT_ENABLE; + + pscr &= ~(MV643XX_ETH_SERIAL_PORT_ENABLE | MV643XX_ETH_FORCE_LINK_PASS); mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); - pscr &= ~MV643XX_ETH_FORCE_LINK_PASS; pscr |= MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX | @@ -1990,7 +1960,8 @@ static void eth_port_start(struct net_device *dev) mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); /* Assign port SDMA configuration */ - mv_write(MV643XX_ETH_SDMA_CONFIG_REG(port_num), mp->port_sdma_config); + mv_write(MV643XX_ETH_SDMA_CONFIG_REG(port_num), + MV643XX_ETH_PORT_SDMA_CONFIG_DEFAULT_VALUE); /* Enable port Rx. */ mv643xx_eth_port_enable_rx(port_num, mp->port_rx_queue_command); diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index f2e5da79dde..a553054e8da 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -321,10 +321,6 @@ struct mv643xx_mib_counters { struct mv643xx_private { int port_num; /* User Ethernet port number */ - u32 port_config; /* User port configuration value*/ - u32 port_config_extend; /* User port config extend value*/ - u32 port_sdma_config; /* User port SDMA config value */ - u32 port_serial_control; /* User port serial control value */ u32 port_tx_queue_command; /* Port active Tx queues summary*/ u32 port_rx_queue_command; /* Port active Rx queues summary*/ -- cgit v1.2.3 From d0f6ecad39266f87913539c52dc624f75cc4b914 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 2 Dec 2005 03:54:44 -0500 Subject: [PATCH] arcnet probing cleanups and fixes make arcnet probing do request_mem_region() for all iomem it's going to access, clean the code up. Signed-off-by: Al Viro --- drivers/net/arcnet/arc-rimi.c | 68 ++++++++++++++++------ drivers/net/arcnet/com90xx.c | 132 ++++++++++++++++++++++++++++++------------ 2 files changed, 143 insertions(+), 57 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c index 38c3f033f73..8c8d6c453c4 100644 --- a/drivers/net/arcnet/arc-rimi.c +++ b/drivers/net/arcnet/arc-rimi.c @@ -97,25 +97,44 @@ static int __init arcrimi_probe(struct net_device *dev) "must specify the shmem and irq!\n"); return -ENODEV; } + if (dev->dev_addr[0] == 0) { + BUGMSG(D_NORMAL, "You need to specify your card's station " + "ID!\n"); + return -ENODEV; + } /* - * Grab the memory region at mem_start for BUFFER_SIZE bytes. + * Grab the memory region at mem_start for MIRROR_SIZE bytes. * Later in arcrimi_found() the real size will be determined * and this reserve will be released and the correct size * will be taken. */ - if (!request_mem_region(dev->mem_start, BUFFER_SIZE, "arcnet (90xx)")) { + if (!request_mem_region(dev->mem_start, MIRROR_SIZE, "arcnet (90xx)")) { BUGMSG(D_NORMAL, "Card memory already allocated\n"); return -ENODEV; } - if (dev->dev_addr[0] == 0) { - release_mem_region(dev->mem_start, BUFFER_SIZE); - BUGMSG(D_NORMAL, "You need to specify your card's station " - "ID!\n"); - return -ENODEV; - } return arcrimi_found(dev); } +static int check_mirror(unsigned long addr, size_t size) +{ + void __iomem *p; + int res = -1; + + if (!request_mem_region(addr, size, "arcnet (90xx)")) + return -1; + + p = ioremap(addr, size); + if (p) { + if (readb(p) == TESTvalue) + res = 1; + else + res = 0; + iounmap(p); + } + + release_mem_region(addr, size); + return res; +} /* * Set up the struct net_device associated with this card. Called after @@ -125,19 +144,28 @@ static int __init arcrimi_found(struct net_device *dev) { struct arcnet_local *lp; unsigned long first_mirror, last_mirror, shmem; + void __iomem *p; int mirror_size; int err; + p = ioremap(dev->mem_start, MIRROR_SIZE); + if (!p) { + release_mem_region(dev->mem_start, MIRROR_SIZE); + BUGMSG(D_NORMAL, "Can't ioremap\n"); + return -ENODEV; + } + /* reserve the irq */ if (request_irq(dev->irq, &arcnet_interrupt, 0, "arcnet (RIM I)", dev)) { - release_mem_region(dev->mem_start, BUFFER_SIZE); + iounmap(p); + release_mem_region(dev->mem_start, MIRROR_SIZE); BUGMSG(D_NORMAL, "Can't get IRQ %d!\n", dev->irq); return -ENODEV; } shmem = dev->mem_start; - isa_writeb(TESTvalue, shmem); - isa_writeb(dev->dev_addr[0], shmem + 1); /* actually the node ID */ + writeb(TESTvalue, p); + writeb(dev->dev_addr[0], p + 1); /* actually the node ID */ /* find the real shared memory start/end points, including mirrors */ @@ -146,17 +174,18 @@ static int __init arcrimi_found(struct net_device *dev) * 2k (or there are no mirrors at all) but on some, it's 4k. */ mirror_size = MIRROR_SIZE; - if (isa_readb(shmem) == TESTvalue - && isa_readb(shmem - mirror_size) != TESTvalue - && isa_readb(shmem - 2 * mirror_size) == TESTvalue) - mirror_size *= 2; + if (readb(p) == TESTvalue + && check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 + && check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1) + mirror_size = 2 * MIRROR_SIZE; - first_mirror = last_mirror = shmem; - while (isa_readb(first_mirror) == TESTvalue) + first_mirror = shmem - mirror_size; + while (check_mirror(first_mirror, mirror_size) == 1) first_mirror -= mirror_size; first_mirror += mirror_size; - while (isa_readb(last_mirror) == TESTvalue) + last_mirror = shmem + mirror_size; + while (check_mirror(last_mirror, mirror_size) == 1) last_mirror += mirror_size; last_mirror -= mirror_size; @@ -181,7 +210,8 @@ static int __init arcrimi_found(struct net_device *dev) * with the correct size. There is a VERY slim chance this could * fail. */ - release_mem_region(shmem, BUFFER_SIZE); + iounmap(p); + release_mem_region(shmem, MIRROR_SIZE); if (!request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)")) { diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c index 6c2c9b9ac6d..43150b2bd13 100644 --- a/drivers/net/arcnet/com90xx.c +++ b/drivers/net/arcnet/com90xx.c @@ -53,7 +53,7 @@ /* Internal function declarations */ -static int com90xx_found(int ioaddr, int airq, u_long shmem); +static int com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *); static void com90xx_command(struct net_device *dev, int command); static int com90xx_status(struct net_device *dev); static void com90xx_setmask(struct net_device *dev, int mask); @@ -116,14 +116,26 @@ static void __init com90xx_probe(void) unsigned long airqmask; int ports[(0x3f0 - 0x200) / 16 + 1] = {0}; - u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] = - {0}; + unsigned long *shmems; + void __iomem **iomem; int numports, numshmems, *port; u_long *p; + int index; if (!io && !irq && !shmem && !*device && com90xx_skip_probe) return; + shmems = kzalloc(((0x10000-0xa0000) / 0x800) * sizeof(unsigned long), + GFP_KERNEL); + if (!shmems) + return; + iomem = kzalloc(((0x10000-0xa0000) / 0x800) * sizeof(void __iomem *), + GFP_KERNEL); + if (!iomem) { + kfree(shmems); + return; + } + BUGLVL(D_NORMAL) printk(VERSION); /* set up the arrays where we'll store the possible probe addresses */ @@ -179,6 +191,8 @@ static void __init com90xx_probe(void) if (!numports) { BUGMSG2(D_NORMAL, "S1: No ARCnet cards found.\n"); + kfree(shmems); + kfree(iomem); return; } /* Stage 2: we have now reset any possible ARCnet cards, so we can't @@ -202,8 +216,8 @@ static void __init com90xx_probe(void) * 0xD1 byte in the right place, or are read-only. */ numprint = -1; - for (p = &shmems[0]; p < shmems + numshmems; p++) { - u_long ptr = *p; + for (index = 0, p = &shmems[0]; index < numshmems; p++, index++) { + void __iomem *base; numprint++; numprint %= 8; @@ -213,38 +227,49 @@ static void __init com90xx_probe(void) } BUGMSG2(D_INIT, "%lXh ", *p); - if (!request_mem_region(*p, BUFFER_SIZE, "arcnet (90xx)")) { + if (!request_mem_region(*p, MIRROR_SIZE, "arcnet (90xx)")) { BUGMSG2(D_INIT_REASONS, "(request_mem_region)\n"); BUGMSG2(D_INIT_REASONS, "Stage 3: "); BUGLVL(D_INIT_REASONS) numprint = 0; - *p-- = shmems[--numshmems]; - continue; + goto out; + } + base = ioremap(*p, MIRROR_SIZE); + if (!base) { + BUGMSG2(D_INIT_REASONS, "(ioremap)\n"); + BUGMSG2(D_INIT_REASONS, "Stage 3: "); + BUGLVL(D_INIT_REASONS) numprint = 0; + goto out1; } - if (isa_readb(ptr) != TESTvalue) { + if (readb(base) != TESTvalue) { BUGMSG2(D_INIT_REASONS, "(%02Xh != %02Xh)\n", - isa_readb(ptr), TESTvalue); + readb(base), TESTvalue); BUGMSG2(D_INIT_REASONS, "S3: "); BUGLVL(D_INIT_REASONS) numprint = 0; - release_mem_region(*p, BUFFER_SIZE); - *p-- = shmems[--numshmems]; - continue; + goto out2; } /* By writing 0x42 to the TESTvalue location, we also make * sure no "mirror" shmem areas show up - if they occur * in another pass through this loop, they will be discarded * because *cptr != TESTvalue. */ - isa_writeb(0x42, ptr); - if (isa_readb(ptr) != 0x42) { + writeb(0x42, base); + if (readb(base) != 0x42) { BUGMSG2(D_INIT_REASONS, "(read only)\n"); BUGMSG2(D_INIT_REASONS, "S3: "); - release_mem_region(*p, BUFFER_SIZE); - *p-- = shmems[--numshmems]; - continue; + goto out2; } BUGMSG2(D_INIT_REASONS, "\n"); BUGMSG2(D_INIT_REASONS, "S3: "); BUGLVL(D_INIT_REASONS) numprint = 0; + iomem[index] = base; + continue; + out2: + iounmap(base); + out1: + release_mem_region(*p, MIRROR_SIZE); + out: + *p-- = shmems[--numshmems]; + index--; } BUGMSG2(D_INIT, "\n"); @@ -252,6 +277,8 @@ static void __init com90xx_probe(void) BUGMSG2(D_NORMAL, "S3: No ARCnet cards found.\n"); for (port = &ports[0]; port < ports + numports; port++) release_region(*port, ARCNET_TOTAL_SIZE); + kfree(shmems); + kfree(iomem); return; } /* Stage 4: something of a dummy, to report the shmems that are @@ -351,30 +378,32 @@ static void __init com90xx_probe(void) mdelay(RESETtime); } else { /* just one shmem and port, assume they match */ - isa_writeb(TESTvalue, shmems[0]); + writeb(TESTvalue, iomem[0]); } #else inb(_RESET); mdelay(RESETtime); #endif - for (p = &shmems[0]; p < shmems + numshmems; p++) { - u_long ptr = *p; + for (index = 0; index < numshmems; index++) { + u_long ptr = shmems[index]; + void __iomem *base = iomem[index]; - if (isa_readb(ptr) == TESTvalue) { /* found one */ + if (readb(base) == TESTvalue) { /* found one */ BUGMSG2(D_INIT, "%lXh)\n", *p); openparen = 0; /* register the card */ - if (com90xx_found(*port, airq, *p) == 0) + if (com90xx_found(*port, airq, ptr, base) == 0) found = 1; numprint = -1; /* remove shmem from the list */ - *p = shmems[--numshmems]; + shmems[index] = shmems[--numshmems]; + iomem[index] = iomem[numshmems]; break; /* go to the next I/O port */ } else { - BUGMSG2(D_INIT_REASONS, "%Xh-", isa_readb(ptr)); + BUGMSG2(D_INIT_REASONS, "%Xh-", readb(base)); } } @@ -391,17 +420,40 @@ static void __init com90xx_probe(void) BUGLVL(D_INIT_REASONS) printk("\n"); /* Now put back TESTvalue on all leftover shmems. */ - for (p = &shmems[0]; p < shmems + numshmems; p++) { - isa_writeb(TESTvalue, *p); - release_mem_region(*p, BUFFER_SIZE); + for (index = 0; index < numshmems; index++) { + writeb(TESTvalue, iomem[index]); + iounmap(iomem[index]); + release_mem_region(shmems[index], MIRROR_SIZE); } + kfree(shmems); + kfree(iomem); } +static int check_mirror(unsigned long addr, size_t size) +{ + void __iomem *p; + int res = -1; + + if (!request_mem_region(addr, size, "arcnet (90xx)")) + return -1; + + p = ioremap(addr, size); + if (p) { + if (readb(p) == TESTvalue) + res = 1; + else + res = 0; + iounmap(p); + } + + release_mem_region(addr, size); + return res; +} /* Set up the struct net_device associated with this card. Called after * probing succeeds. */ -static int __init com90xx_found(int ioaddr, int airq, u_long shmem) +static int __init com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *p) { struct net_device *dev = NULL; struct arcnet_local *lp; @@ -412,7 +464,8 @@ static int __init com90xx_found(int ioaddr, int airq, u_long shmem) dev = alloc_arcdev(device); if (!dev) { BUGMSG2(D_NORMAL, "com90xx: Can't allocate device!\n"); - release_mem_region(shmem, BUFFER_SIZE); + iounmap(p); + release_mem_region(shmem, MIRROR_SIZE); return -ENOMEM; } lp = dev->priv; @@ -423,24 +476,27 @@ static int __init com90xx_found(int ioaddr, int airq, u_long shmem) * 2k (or there are no mirrors at all) but on some, it's 4k. */ mirror_size = MIRROR_SIZE; - if (isa_readb(shmem) == TESTvalue - && isa_readb(shmem - mirror_size) != TESTvalue - && isa_readb(shmem - 2 * mirror_size) == TESTvalue) - mirror_size *= 2; + if (readb(p) == TESTvalue && + check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 && + check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1) + mirror_size = 2 * MIRROR_SIZE; - first_mirror = last_mirror = shmem; - while (isa_readb(first_mirror) == TESTvalue) + first_mirror = shmem - mirror_size; + while (check_mirror(first_mirror, mirror_size) == 1) first_mirror -= mirror_size; first_mirror += mirror_size; - while (isa_readb(last_mirror) == TESTvalue) + last_mirror = shmem + mirror_size; + while (check_mirror(last_mirror, mirror_size) == 1) last_mirror += mirror_size; last_mirror -= mirror_size; dev->mem_start = first_mirror; dev->mem_end = last_mirror + MIRROR_SIZE - 1; - release_mem_region(shmem, BUFFER_SIZE); + iounmap(p); + release_mem_region(shmem, MIRROR_SIZE); + if (!request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)")) goto err_free_dev; -- cgit v1.2.3 From b43de2d8db7655d1c520bf6eac7071d8f6d0b864 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 1 Dec 2005 10:15:21 -0500 Subject: [PATCH] ibm_emac sparse annotations Signed-off-by: Al Viro --- drivers/net/ibm_emac/ibm_emac_core.c | 40 +++++++++++++++++------------------ drivers/net/ibm_emac/ibm_emac_core.h | 2 +- drivers/net/ibm_emac/ibm_emac_debug.c | 2 +- drivers/net/ibm_emac/ibm_emac_rgmii.h | 2 +- drivers/net/ibm_emac/ibm_emac_zmii.c | 7 +++--- drivers/net/ibm_emac/ibm_emac_zmii.h | 2 +- 6 files changed, 26 insertions(+), 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c index 591c5864ffb..7e49522b8b3 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.c +++ b/drivers/net/ibm_emac/ibm_emac_core.c @@ -204,7 +204,7 @@ static inline int emac_phy_gpcs(int phy_mode) static inline void emac_tx_enable(struct ocp_enet_private *dev) { - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; unsigned long flags; u32 r; @@ -220,7 +220,7 @@ static inline void emac_tx_enable(struct ocp_enet_private *dev) static void emac_tx_disable(struct ocp_enet_private *dev) { - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; unsigned long flags; u32 r; @@ -244,7 +244,7 @@ static void emac_tx_disable(struct ocp_enet_private *dev) static void emac_rx_enable(struct ocp_enet_private *dev) { - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; unsigned long flags; u32 r; @@ -275,7 +275,7 @@ static void emac_rx_enable(struct ocp_enet_private *dev) static void emac_rx_disable(struct ocp_enet_private *dev) { - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; unsigned long flags; u32 r; @@ -299,7 +299,7 @@ static void emac_rx_disable(struct ocp_enet_private *dev) static inline void emac_rx_disable_async(struct ocp_enet_private *dev) { - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; unsigned long flags; u32 r; @@ -315,7 +315,7 @@ static inline void emac_rx_disable_async(struct ocp_enet_private *dev) static int emac_reset(struct ocp_enet_private *dev) { - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; unsigned long flags; int n = 20; @@ -348,7 +348,7 @@ static int emac_reset(struct ocp_enet_private *dev) static void emac_hash_mc(struct ocp_enet_private *dev) { - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; u16 gaht[4] = { 0 }; struct dev_mc_list *dmi; @@ -393,7 +393,7 @@ static inline int emac_opb_mhz(void) /* BHs disabled */ static int emac_configure(struct ocp_enet_private *dev) { - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; struct net_device *ndev = dev->ndev; int gige; u32 r; @@ -555,7 +555,7 @@ static void emac_full_tx_reset(struct net_device *ndev) static int __emac_mdio_read(struct ocp_enet_private *dev, u8 id, u8 reg) { - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; u32 r; int n; @@ -604,7 +604,7 @@ static int __emac_mdio_read(struct ocp_enet_private *dev, u8 id, u8 reg) static void __emac_mdio_write(struct ocp_enet_private *dev, u8 id, u8 reg, u16 val) { - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; int n; DBG2("%d: mdio_write(%02x,%02x,%04x)" NL, dev->def->index, id, reg, @@ -666,7 +666,7 @@ static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val) static void emac_set_multicast_list(struct net_device *ndev) { struct ocp_enet_private *dev = ndev->priv; - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; u32 rmr = emac_iff2rmr(ndev); DBG("%d: multicast %08x" NL, dev->def->index, rmr); @@ -825,7 +825,7 @@ static void emac_clean_rx_ring(struct ocp_enet_private *dev) } static inline int emac_alloc_rx_skb(struct ocp_enet_private *dev, int slot, - int flags) + gfp_t flags) { struct sk_buff *skb = alloc_skb(dev->rx_skb_size, flags); if (unlikely(!skb)) @@ -1047,7 +1047,7 @@ static inline u16 emac_tx_csum(struct ocp_enet_private *dev, static inline int emac_xmit_finish(struct ocp_enet_private *dev, int len) { - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; struct net_device *ndev = dev->ndev; /* Send the packet out */ @@ -1519,7 +1519,7 @@ static void emac_rxde(void *param) static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs) { struct ocp_enet_private *dev = dev_instance; - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; struct ibm_emac_error_stats *st = &dev->estats; u32 isr = in_be32(&p->isr); @@ -1619,17 +1619,17 @@ static void emac_remove(struct ocp_device *ocpdev) DBG("%d: remove" NL, dev->def->index); - ocp_set_drvdata(ocpdev, 0); + ocp_set_drvdata(ocpdev, NULL); unregister_netdev(dev->ndev); tah_fini(dev->tah_dev); rgmii_fini(dev->rgmii_dev, dev->rgmii_input); zmii_fini(dev->zmii_dev, dev->zmii_input); - emac_dbg_register(dev->def->index, 0); + emac_dbg_register(dev->def->index, NULL); mal_unregister_commac(dev->mal, &dev->commac); - iounmap((void *)dev->emacp); + iounmap(dev->emacp); kfree(dev->ndev); } @@ -2048,9 +2048,7 @@ static int __init emac_probe(struct ocp_device *ocpdev) goto out4; /* Map EMAC regs */ - dev->emacp = - (struct emac_regs *)ioremap(dev->def->paddr, - sizeof(struct emac_regs)); + dev->emacp = ioremap(dev->def->paddr, sizeof(struct emac_regs)); if (!dev->emacp) { printk(KERN_ERR "emac%d: could not ioremap device registers!\n", dev->def->index); @@ -2210,7 +2208,7 @@ static int __init emac_probe(struct ocp_device *ocpdev) return 0; out6: - iounmap((void *)dev->emacp); + iounmap(dev->emacp); out5: tah_fini(dev->tah_dev); out4: diff --git a/drivers/net/ibm_emac/ibm_emac_core.h b/drivers/net/ibm_emac/ibm_emac_core.h index 911abbaf471..f61273b2e94 100644 --- a/drivers/net/ibm_emac/ibm_emac_core.h +++ b/drivers/net/ibm_emac/ibm_emac_core.h @@ -155,7 +155,7 @@ struct ibm_emac_error_stats { struct ocp_enet_private { struct net_device *ndev; /* 0 */ - struct emac_regs *emacp; + struct emac_regs __iomem *emacp; struct mal_descriptor *tx_desc; int tx_cnt; diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c index 75d3b863904..c7e1ecfa08f 100644 --- a/drivers/net/ibm_emac/ibm_emac_debug.c +++ b/drivers/net/ibm_emac/ibm_emac_debug.c @@ -58,7 +58,7 @@ static void emac_desc_dump(int idx, struct ocp_enet_private *p) static void emac_mac_dump(int idx, struct ocp_enet_private *dev) { - struct emac_regs *p = dev->emacp; + struct emac_regs __iomem *p = dev->emacp; printk("** EMAC%d registers **\n" "MR0 = 0x%08x MR1 = 0x%08x TMR0 = 0x%08x TMR1 = 0x%08x\n" diff --git a/drivers/net/ibm_emac/ibm_emac_rgmii.h b/drivers/net/ibm_emac/ibm_emac_rgmii.h index a1ffb8a44ff..7f03d536c9a 100644 --- a/drivers/net/ibm_emac/ibm_emac_rgmii.h +++ b/drivers/net/ibm_emac/ibm_emac_rgmii.h @@ -31,7 +31,7 @@ struct rgmii_regs { /* RGMII device */ struct ibm_ocp_rgmii { - struct rgmii_regs *base; + struct rgmii_regs __iomem *base; int users; /* number of EMACs using this RGMII bridge */ }; diff --git a/drivers/net/ibm_emac/ibm_emac_zmii.c b/drivers/net/ibm_emac/ibm_emac_zmii.c index 35c1185079e..e129e0aaa04 100644 --- a/drivers/net/ibm_emac/ibm_emac_zmii.c +++ b/drivers/net/ibm_emac/ibm_emac_zmii.c @@ -80,7 +80,7 @@ static inline u32 zmii_mode_mask(int mode, int input) static int __init zmii_init(struct ocp_device *ocpdev, int input, int *mode) { struct ibm_ocp_zmii *dev = ocp_get_drvdata(ocpdev); - struct zmii_regs *p; + struct zmii_regs __iomem *p; ZMII_DBG("%d: init(%d, %d)" NL, ocpdev->def->index, input, *mode); @@ -94,8 +94,7 @@ static int __init zmii_init(struct ocp_device *ocpdev, int input, int *mode) } dev->mode = PHY_MODE_NA; - p = (struct zmii_regs *)ioremap(ocpdev->def->paddr, - sizeof(struct zmii_regs)); + p = ioremap(ocpdev->def->paddr, sizeof(struct zmii_regs)); if (!p) { printk(KERN_ERR "zmii%d: could not ioremap device registers!\n", @@ -231,7 +230,7 @@ void __exit __zmii_fini(struct ocp_device *ocpdev, int input) if (!--dev->users) { /* Free everything if this is the last user */ ocp_set_drvdata(ocpdev, NULL); - iounmap((void *)dev->base); + iounmap(dev->base); kfree(dev); } } diff --git a/drivers/net/ibm_emac/ibm_emac_zmii.h b/drivers/net/ibm_emac/ibm_emac_zmii.h index 0bb26062c0a..92c85441075 100644 --- a/drivers/net/ibm_emac/ibm_emac_zmii.h +++ b/drivers/net/ibm_emac/ibm_emac_zmii.h @@ -32,7 +32,7 @@ struct zmii_regs { /* ZMII device */ struct ibm_ocp_zmii { - struct zmii_regs *base; + struct zmii_regs __iomem *base; int mode; /* subset of PHY_MODE_XXXX */ int users; /* number of EMACs using this ZMII bridge */ u32 fer_save; /* FER value left by firmware */ -- cgit v1.2.3 From 976345cc0fb34d677233b5b22d4819dc7ac92ef1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 6 Dec 2005 06:02:45 -0500 Subject: [PATCH] appletalk/cops.h: missing const in struct ltfirmware Signed-off-by: Al Viro --- drivers/net/appletalk/cops.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/appletalk/cops.h b/drivers/net/appletalk/cops.h index c68ba9c2ef4..aca47f3a7b9 100644 --- a/drivers/net/appletalk/cops.h +++ b/drivers/net/appletalk/cops.h @@ -51,7 +51,7 @@ struct ltfirmware { unsigned int length; - unsigned char * data; + const unsigned char * data; }; #define DAYNA 1 -- cgit v1.2.3 From ded5ca1f3b9ffa464fe5d4744fd09bba753ff4b7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 4 Dec 2005 02:28:40 -0500 Subject: [PATCH] macsonic.c: missed s/driver_unregister/platform_driver_unregister/ Signed-off-by: Al Viro --- drivers/net/macsonic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index 02d5c682273..f6f3dafe83e 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -622,7 +622,7 @@ static int __init mac_sonic_init_module(void) return 0; out_unregister: - driver_unregister(&mac_sonic_driver); + platform_driver_unregister(&mac_sonic_driver); return -ENOMEM; } -- cgit v1.2.3 From 82729971e0f8ccf1f15567cc4f2c5389e0659eb2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 6 Dec 2005 05:53:04 -0500 Subject: [PATCH] missing include of asm/irq.h in drivers/net Signed-off-by: Al Viro --- drivers/net/tulip/xircom_cb.c | 3 +++ drivers/net/wan/hostess_sv11.c | 1 + drivers/net/wan/sealevel.c | 1 + 3 files changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 60d1e05ab73..42e9ffb07af 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -32,6 +32,9 @@ #include #include +#ifdef CONFIG_NET_POLL_CONTROLLER +#include +#endif #ifdef DEBUG #define enter(x) printk("Enter: %s, %s line %i\n",x,__FILE__,__LINE__) diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index 7db1d1d0bb3..cf5c805452a 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c index 5380ddfcd7d..050e854e777 100644 --- a/drivers/net/wan/sealevel.c +++ b/drivers/net/wan/sealevel.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include -- cgit v1.2.3 From 3c13958620f08c8082a2694e51dec32592438388 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 1 Dec 2005 06:44:55 -0500 Subject: [PATCH] bogus include of linux/irq.h in 7990.c Signed-off-by: Al Viro --- drivers/net/7990.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/7990.c b/drivers/net/7990.c index 18b027e73f2..86633c5f1a4 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include /* Used for the temporal inet entries and routing */ #include #include -- cgit v1.2.3 From 0018dfa48e171315ce7f0ea689e34b67af926e19 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 1 Dec 2005 06:53:59 -0500 Subject: [PATCH] wrong ifdefs in 82596.c ifdefs around variable declaration would better match those around its uses... Signed-off-by: Al Viro --- drivers/net/82596.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/82596.c b/drivers/net/82596.c index 13b745b3966..da0c878dcba 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -614,7 +614,7 @@ static void rebuild_rx_bufs(struct net_device *dev) static int init_i596_mem(struct net_device *dev) { struct i596_private *lp = dev->priv; -#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) +#if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) || defined(ENABLE_APRICOT) short ioaddr = dev->base_addr; #endif unsigned long flags; -- cgit v1.2.3 From 450d86dff3fc4780fd5c2d1654402ab7ffec9c38 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 22 Dec 2005 14:52:52 -0500 Subject: [PATCH] dead code removed in hp100 for mode 2 (memory-mapped) we always set ->mem_ptr_virt; dead code removed. Signed-off-by: Al Viro --- drivers/net/hp100.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 55c7ed60839..7ba87b7ee61 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -1718,17 +1718,10 @@ static int hp100_start_xmit(struct sk_buff *skb, struct net_device *dev) hp100_outw(i, FRAGMENT_LEN); /* and first/only fragment length */ if (lp->mode == 2) { /* memory mapped */ - if (lp->mem_ptr_virt) { /* high pci memory was remapped */ - /* Note: The J2585B needs alignment to 32bits here! */ - memcpy_toio(lp->mem_ptr_virt, skb->data, (skb->len + 3) & ~3); - if (!ok_flag) - memset_io(lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len); - } else { - /* Note: The J2585B needs alignment to 32bits here! */ - isa_memcpy_toio(lp->mem_ptr_phys, skb->data, (skb->len + 3) & ~3); - if (!ok_flag) - isa_memset_io(lp->mem_ptr_phys, 0, HP100_MIN_PACKET_SIZE - skb->len); - } + /* Note: The J2585B needs alignment to 32bits here! */ + memcpy_toio(lp->mem_ptr_virt, skb->data, (skb->len + 3) & ~3); + if (!ok_flag) + memset_io(lp->mem_ptr_virt, 0, HP100_MIN_PACKET_SIZE - skb->len); } else { /* programmed i/o */ outsl(ioaddr + HP100_REG_DATA32, skb->data, (skb->len + 3) >> 2); @@ -1798,10 +1791,7 @@ static void hp100_rx(struct net_device *dev) /* First we get the header, which contains information about the */ /* actual length of the received packet. */ if (lp->mode == 2) { /* memory mapped mode */ - if (lp->mem_ptr_virt) /* if memory was remapped */ - header = readl(lp->mem_ptr_virt); - else - header = isa_readl(lp->mem_ptr_phys); + header = readl(lp->mem_ptr_virt); } else /* programmed i/o */ header = hp100_inl(DATA32); @@ -1833,13 +1823,9 @@ static void hp100_rx(struct net_device *dev) ptr = skb->data; /* Now transfer the data from the card into that area */ - if (lp->mode == 2) { - if (lp->mem_ptr_virt) - memcpy_fromio(ptr, lp->mem_ptr_virt,pkt_len); - /* Note alignment to 32bit transfers */ - else - isa_memcpy_fromio(ptr, lp->mem_ptr_phys, pkt_len); - } else /* io mapped */ + if (lp->mode == 2) + memcpy_fromio(ptr, lp->mem_ptr_virt,pkt_len); + else /* io mapped */ insl(ioaddr + HP100_REG_DATA32, ptr, pkt_len >> 2); skb->protocol = eth_type_trans(skb, dev); -- cgit v1.2.3 From d86b5e0e6bf5980d3136ab4a855522143f2dcb5d Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 21 Jan 2006 00:46:55 +0100 Subject: [PATCH] net/: fix the WIRELESS_EXT abuse This patch contains the following changes: - add a CONFIG_WIRELESS_EXT select'ed by NET_RADIO for conditional code - remove the now no longer required #ifdef CONFIG_NET_RADIO from some #include's Based on a patch by Jean Tourrilhes . Signed-off-by: Adrian Bunk Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 3 ++- drivers/net/wireless/netwave_cs.c | 2 -- drivers/net/wireless/wavelan.p.h | 6 +----- drivers/net/wireless/wavelan_cs.p.h | 9 +-------- 4 files changed, 4 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 233a4f60808..9ccfec50f73 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -6,7 +6,8 @@ menu "Wireless LAN (non-hamradio)" depends on NETDEVICES config NET_RADIO - bool "Wireless LAN drivers (non-hamradio) & Wireless Extensions" + bool "Wireless LAN drivers (non-hamradio)" + select WIRELESS_EXT ---help--- Support for wireless LANs and everything having to do with radio, but not with amateur radio or FM broadcasting. diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index bf6271ee387..75ce6ddb0cf 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -55,10 +55,8 @@ #include #include #include -#ifdef CONFIG_NET_RADIO #include #include -#endif #include #include diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h index 166e28b9a4f..5cb0bc8bb12 100644 --- a/drivers/net/wireless/wavelan.p.h +++ b/drivers/net/wireless/wavelan.p.h @@ -98,11 +98,7 @@ * characteristics of the hardware. Applications such as mobile IP may * take advantage of it. * - * You will need to enable the CONFIG_NET_RADIO define in the kernel - * configuration to enable the wireless extensions (this is the one - * giving access to the radio network device choice). - * - * It might also be a good idea as well to fetch the wireless tools to + * It might be a good idea as well to fetch the wireless tools to * configure the device and play a bit. */ diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index f2d59756815..451f6271dcb 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h @@ -99,11 +99,7 @@ * caracteristics of the hardware in a standard way and support for * applications for taking advantage of it (like Mobile IP). * - * You will need to enable the CONFIG_NET_RADIO define in the kernel - * configuration to enable the wireless extensions (this is the one - * giving access to the radio network device choice). - * - * It might also be a good idea as well to fetch the wireless tools to + * It might be a good idea as well to fetch the wireless tools to * configure the device and play a bit. */ @@ -440,11 +436,8 @@ #include #include #include - -#ifdef CONFIG_NET_RADIO #include /* Wireless extensions */ #include /* New driver API */ -#endif /* Pcmcia headers that we need */ #include -- cgit v1.2.3 From a39d3e796cd2df8576c0418faa2c3833153bb3a9 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 21 Jan 2006 01:35:15 +0100 Subject: [PATCH] AIRO{,_CS} <-> CRYPTO fixes CRYPTO is a helper variable, and to make it easier for users, it should therefore select'ed and not be listed in the dependencies. drivers/net/wireless/airo.c requires CONFIG_CRYPTO for compilations. Therefore, AIRO_CS also has to CRYPTO. Additionally, this patch removes the #ifdef's for the non-compiling CRYPTO=n case from drivers/net/wireless/airo.c. Signed-off-by: Adrian Bunk Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 4 +++- drivers/net/wireless/airo.c | 55 ++------------------------------------------ 2 files changed, 5 insertions(+), 54 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 9ccfec50f73..3de5f1d0fba 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -240,7 +240,8 @@ config IPW2200_DEBUG config AIRO tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" - depends on NET_RADIO && ISA_DMA_API && CRYPTO && (PCI || BROKEN) + depends on NET_RADIO && ISA_DMA_API && (PCI || BROKEN) + select CRYPTO ---help--- This is the standard Linux driver to support Cisco/Aironet ISA and PCI 802.11 wireless cards. @@ -388,6 +389,7 @@ config PCMCIA_SPECTRUM config AIRO_CS tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" depends on NET_RADIO && PCMCIA && (BROKEN || !M32R) + select CRYPTO ---help--- This is the standard Linux driver to support Cisco/Aironet PCMCIA 802.11 wireless cards. This driver is the same as the Aironet diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index a4c7ae94614..9c577f7b6e5 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -87,14 +88,6 @@ static struct pci_driver airo_driver = { #include #endif -/* Support Cisco MIC feature */ -#define MICSUPPORT - -#if defined(MICSUPPORT) && !defined(CONFIG_CRYPTO) -#warning MIC support requires Crypto API -#undef MICSUPPORT -#endif - /* Hack to do some power saving */ #define POWER_ON_DOWN @@ -1118,7 +1111,6 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp); static int writerids(struct net_device *dev, aironet_ioctl *comp); static int flashcard(struct net_device *dev, aironet_ioctl *comp); #endif /* CISCO_EXT */ -#ifdef MICSUPPORT static void micinit(struct airo_info *ai); static int micsetup(struct airo_info *ai); static int encapsulate(struct airo_info *ai, etherHead *pPacket, MICBuffer *buffer, int len); @@ -1127,9 +1119,6 @@ static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi); static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm); -#include -#endif - struct airo_info { struct net_device_stats stats; struct net_device *dev; @@ -1190,12 +1179,10 @@ struct airo_info { unsigned long scan_timestamp; /* Time started to scan */ struct iw_spy_data spy_data; struct iw_public_data wireless_data; -#ifdef MICSUPPORT /* MIC stuff */ struct crypto_tfm *tfm; mic_module mod[2]; mic_statistics micstats; -#endif HostRxDesc rxfids[MPI_MAX_FIDS]; // rx/tx/config MPI350 descriptors HostTxDesc txfids[MPI_MAX_FIDS]; HostRidDesc config_desc; @@ -1229,7 +1216,6 @@ static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime); static int flashputbuf(struct airo_info *ai); static int flashrestart(struct airo_info *ai,struct net_device *dev); -#ifdef MICSUPPORT /*********************************************************************** * MIC ROUTINES * *********************************************************************** @@ -1686,7 +1672,6 @@ static void emmh32_final(emmh32_context *context, u8 digest[4]) digest[2] = (val>>8) & 0xFF; digest[3] = val & 0xFF; } -#endif static int readBSSListRid(struct airo_info *ai, int first, BSSListRid *list) { @@ -2005,7 +1990,6 @@ static int mpi_send_packet (struct net_device *dev) * Firmware automaticly puts 802 header on so * we don't need to account for it in the length */ -#ifdef MICSUPPORT if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && (ntohs(((u16 *)buffer)[6]) != 0x888E)) { MICBuffer pMic; @@ -2022,9 +2006,7 @@ static int mpi_send_packet (struct net_device *dev) memcpy (sendbuf, &pMic, sizeof(pMic)); sendbuf += sizeof(pMic); memcpy (sendbuf, buffer, len - sizeof(etherHead)); - } else -#endif - { + } else { *payloadLen = cpu_to_le16(len - sizeof(etherHead)); dev->trans_start = jiffies; @@ -2400,9 +2382,7 @@ void stop_airo_card( struct net_device *dev, int freeres ) ai->shared, ai->shared_dma); } } -#ifdef MICSUPPORT crypto_free_tfm(ai->tfm); -#endif del_airo_dev( dev ); free_netdev( dev ); } @@ -2726,9 +2706,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, ai->thr_pid = kernel_thread(airo_thread, dev, CLONE_FS | CLONE_FILES); if (ai->thr_pid < 0) goto err_out_free; -#ifdef MICSUPPORT ai->tfm = NULL; -#endif rc = add_airo_dev( dev ); if (rc) goto err_out_thr; @@ -2969,10 +2947,8 @@ static int airo_thread(void *data) { airo_read_wireless_stats(ai); else if (test_bit(JOB_PROMISC, &ai->flags)) airo_set_promisc(ai); -#ifdef MICSUPPORT else if (test_bit(JOB_MIC, &ai->flags)) micinit(ai); -#endif else if (test_bit(JOB_EVENT, &ai->flags)) airo_send_event(dev); else if (test_bit(JOB_AUTOWEP, &ai->flags)) @@ -3010,12 +2986,10 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) if ( status & EV_MIC ) { OUT4500( apriv, EVACK, EV_MIC ); -#ifdef MICSUPPORT if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) { set_bit(JOB_MIC, &apriv->flags); wake_up_interruptible(&apriv->thr_wait); } -#endif } if ( status & EV_LINK ) { union iwreq_data wrqu; @@ -3194,11 +3168,8 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) } bap_read (apriv, buffer + hdrlen/2, len, BAP0); } else { -#ifdef MICSUPPORT MICBuffer micbuf; -#endif bap_read (apriv, buffer, ETH_ALEN*2, BAP0); -#ifdef MICSUPPORT if (apriv->micstats.enabled) { bap_read (apriv,(u16*)&micbuf,sizeof(micbuf),BAP0); if (ntohs(micbuf.typelen) > 0x05DC) @@ -3211,15 +3182,10 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) skb_trim (skb, len + hdrlen); } } -#endif bap_read(apriv,buffer+ETH_ALEN,len,BAP0); -#ifdef MICSUPPORT if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) { badmic: dev_kfree_skb_irq (skb); -#else - if (0) { -#endif badrx: OUT4500( apriv, EVACK, EV_RX); goto exitrx; @@ -3430,10 +3396,8 @@ static void mpi_receive_802_3(struct airo_info *ai) int len = 0; struct sk_buff *skb; char *buffer; -#ifdef MICSUPPORT int off = 0; MICBuffer micbuf; -#endif memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); /* Make sure we got something */ @@ -3448,7 +3412,6 @@ static void mpi_receive_802_3(struct airo_info *ai) goto badrx; } buffer = skb_put(skb,len); -#ifdef MICSUPPORT memcpy(buffer, ai->rxfids[0].virtual_host_addr, ETH_ALEN * 2); if (ai->micstats.enabled) { memcpy(&micbuf, @@ -3470,9 +3433,6 @@ badmic: dev_kfree_skb_irq (skb); goto badrx; } -#else - memcpy(buffer, ai->rxfids[0].virtual_host_addr, len); -#endif #ifdef WIRELESS_SPY if (ai->spy_data.spy_number > 0) { char *sa; @@ -3689,13 +3649,11 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) ai->config.authType = AUTH_OPEN; ai->config.modulation = MOD_CCK; -#ifdef MICSUPPORT if ((cap_rid.len>=sizeof(cap_rid)) && (cap_rid.extSoftCap&1) && (micsetup(ai) == SUCCESS)) { ai->config.opmode |= MODE_MIC; set_bit(FLAG_MIC_CAPABLE, &ai->flags); } -#endif /* Save off the MAC */ for( i = 0; i < ETH_ALEN; i++ ) { @@ -4170,15 +4128,12 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket) } len -= ETH_ALEN * 2; -#ifdef MICSUPPORT if (test_bit(FLAG_MIC_CAPABLE, &ai->flags) && ai->micstats.enabled && (ntohs(((u16 *)pPacket)[6]) != 0x888E)) { if (encapsulate(ai,(etherHead *)pPacket,&pMic,len) != SUCCESS) return ERROR; miclen = sizeof(pMic); } -#endif - // packet is destination[6], source[6], payload[len-12] // write the payload length and dst/src/payload if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR; @@ -7270,13 +7225,11 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { case AIROGSTAT: ridcode = RID_STATUS; break; case AIROGSTATSD32: ridcode = RID_STATSDELTA; break; case AIROGSTATSC32: ridcode = RID_STATS; break; -#ifdef MICSUPPORT case AIROGMICSTATS: if (copy_to_user(comp->data, &ai->micstats, min((int)comp->len,(int)sizeof(ai->micstats)))) return -EFAULT; return 0; -#endif case AIRORRID: ridcode = comp->ridnum; break; default: return -EINVAL; @@ -7308,9 +7261,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { static int writerids(struct net_device *dev, aironet_ioctl *comp) { struct airo_info *ai = dev->priv; int ridcode; -#ifdef MICSUPPORT int enabled; -#endif Resp rsp; static int (* writer)(struct airo_info *, u16 rid, const void *, int, int); unsigned char *iobuf; @@ -7367,11 +7318,9 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) { PC4500_readrid(ai,RID_STATSDELTACLEAR,iobuf,RIDSIZE, 1); -#ifdef MICSUPPORT enabled = ai->micstats.enabled; memset(&ai->micstats,0,sizeof(ai->micstats)); ai->micstats.enabled = enabled; -#endif if (copy_to_user(comp->data, iobuf, min((int)comp->len, (int)RIDSIZE))) { -- cgit v1.2.3 From 3c398b8612b210a159ec7ba5e5c3c341fb0d5eab Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 21 Jan 2006 01:36:36 +0100 Subject: [PATCH] drivers/net/wireless/ipw2100.c: make ipw2100_wpa_assoc_frame() static This patch makes the needlessly global ipw2100_wpa_assoc_frame() static. Signed-off-by: Adrian Bunk Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 6290c9f7e93..31c262c314c 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -5771,8 +5771,8 @@ static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value) return ret; } -void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv, - char *wpa_ie, int wpa_ie_len) +static void ipw2100_wpa_assoc_frame(struct ipw2100_priv *priv, + char *wpa_ie, int wpa_ie_len) { struct ipw2100_wpa_assoc_frame frame; -- cgit v1.2.3 From a73e22b286bd162d10526521b34f2d6f37aac635 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 21 Jan 2006 01:39:42 +0100 Subject: [PATCH] drivers/net/wireless/ipw2200: possible cleanups This patch contains the following possible cleanups: - make needlessly global functions static - "extern inline" -> "static inline" - #if 0 the unused global function ipw_led_activity_on() Signed-off-by: Adrian Bunk Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 33 ++++++++++++++++++--------------- drivers/net/wireless/ipw2200.h | 4 ++-- 2 files changed, 20 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 916b24c544e..2a834deb60e 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -701,7 +701,7 @@ static void ipw_init_ordinals(struct ipw_priv *priv) } -u32 ipw_register_toggle(u32 reg) +static u32 ipw_register_toggle(u32 reg) { reg &= ~IPW_START_STANDBY; if (reg & IPW_GATE_ODMA) @@ -726,7 +726,7 @@ u32 ipw_register_toggle(u32 reg) #define LD_TIME_LINK_OFF 2700 #define LD_TIME_ACT_ON 250 -void ipw_led_link_on(struct ipw_priv *priv) +static void ipw_led_link_on(struct ipw_priv *priv) { unsigned long flags; u32 led; @@ -769,7 +769,7 @@ static void ipw_bg_led_link_on(void *data) up(&priv->sem); } -void ipw_led_link_off(struct ipw_priv *priv) +static void ipw_led_link_off(struct ipw_priv *priv) { unsigned long flags; u32 led; @@ -847,6 +847,7 @@ static void __ipw_led_activity_on(struct ipw_priv *priv) } } +#if 0 void ipw_led_activity_on(struct ipw_priv *priv) { unsigned long flags; @@ -854,8 +855,9 @@ void ipw_led_activity_on(struct ipw_priv *priv) __ipw_led_activity_on(priv); spin_unlock_irqrestore(&priv->lock, flags); } +#endif /* 0 */ -void ipw_led_activity_off(struct ipw_priv *priv) +static void ipw_led_activity_off(struct ipw_priv *priv) { unsigned long flags; u32 led; @@ -890,7 +892,7 @@ static void ipw_bg_led_activity_off(void *data) up(&priv->sem); } -void ipw_led_band_on(struct ipw_priv *priv) +static void ipw_led_band_on(struct ipw_priv *priv) { unsigned long flags; u32 led; @@ -925,7 +927,7 @@ void ipw_led_band_on(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -void ipw_led_band_off(struct ipw_priv *priv) +static void ipw_led_band_off(struct ipw_priv *priv) { unsigned long flags; u32 led; @@ -948,24 +950,24 @@ void ipw_led_band_off(struct ipw_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -void ipw_led_radio_on(struct ipw_priv *priv) +static void ipw_led_radio_on(struct ipw_priv *priv) { ipw_led_link_on(priv); } -void ipw_led_radio_off(struct ipw_priv *priv) +static void ipw_led_radio_off(struct ipw_priv *priv) { ipw_led_activity_off(priv); ipw_led_link_off(priv); } -void ipw_led_link_up(struct ipw_priv *priv) +static void ipw_led_link_up(struct ipw_priv *priv) { /* Set the Link Led on for all nic types */ ipw_led_link_on(priv); } -void ipw_led_link_down(struct ipw_priv *priv) +static void ipw_led_link_down(struct ipw_priv *priv) { ipw_led_activity_off(priv); ipw_led_link_off(priv); @@ -974,7 +976,7 @@ void ipw_led_link_down(struct ipw_priv *priv) ipw_led_radio_off(priv); } -void ipw_led_init(struct ipw_priv *priv) +static void ipw_led_init(struct ipw_priv *priv) { priv->nic_type = priv->eeprom[EEPROM_NIC_TYPE]; @@ -1025,7 +1027,7 @@ void ipw_led_init(struct ipw_priv *priv) } } -void ipw_led_shutdown(struct ipw_priv *priv) +static void ipw_led_shutdown(struct ipw_priv *priv) { ipw_led_activity_off(priv); ipw_led_link_off(priv); @@ -6204,7 +6206,8 @@ static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) return ret; } -void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, int wpa_ie_len) +static void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, + int wpa_ie_len) { /* make sure WPA is enabled */ ipw_wpa_enable(priv, 1); @@ -10059,7 +10062,7 @@ static void ipw_bg_rf_kill(void *data) up(&priv->sem); } -void ipw_link_up(struct ipw_priv *priv) +static void ipw_link_up(struct ipw_priv *priv) { priv->last_seq_num = -1; priv->last_frag_num = -1; @@ -10094,7 +10097,7 @@ static void ipw_bg_link_up(void *data) up(&priv->sem); } -void ipw_link_down(struct ipw_priv *priv) +static void ipw_link_down(struct ipw_priv *priv) { ipw_led_link_down(priv); netif_carrier_off(priv->net_dev); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index e65620a4d79..e2afa76ad3c 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -852,7 +852,7 @@ struct ipw_scan_request_ext { u16 dwell_time[IPW_SCAN_TYPES]; } __attribute__ ((packed)); -extern inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index) +static inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index) { if (index % 2) return scan->scan_type[index / 2] & 0x0F; @@ -860,7 +860,7 @@ extern inline u8 ipw_get_scan_type(struct ipw_scan_request_ext *scan, u8 index) return (scan->scan_type[index / 2] & 0xF0) >> 4; } -extern inline void ipw_set_scan_type(struct ipw_scan_request_ext *scan, +static inline void ipw_set_scan_type(struct ipw_scan_request_ext *scan, u8 index, u8 scan_type) { if (index % 2) -- cgit v1.2.3 From cbbdd03fadeddd02efec05ccfd4e6870ed913762 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 13:48:53 +0800 Subject: [PATCH] ipw2100: Add LEAP authentication algorithm support Signed-off-by: Hong Liu Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 12 +++++++++--- drivers/net/wireless/ipw2100.h | 6 ++++-- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 31c262c314c..b73af778958 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -5365,9 +5365,12 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode) SEC_LEVEL_0, 0, 1); } else { auth_mode = IPW_AUTH_OPEN; - if ((priv->ieee->sec.flags & SEC_AUTH_MODE) && - (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)) - auth_mode = IPW_AUTH_SHARED; + if (priv->ieee->sec.flags & SEC_AUTH_MODE) { + if (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY) + auth_mode = IPW_AUTH_SHARED; + else if (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP) + auth_mode = IPW_AUTH_LEAP_CISCO_ID; + } sec_level = SEC_LEVEL_0; if (priv->ieee->sec.flags & SEC_LEVEL) @@ -5760,6 +5763,9 @@ static int ipw2100_wpa_set_auth_algs(struct ipw2100_priv *priv, int value) } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) { sec.auth_mode = WLAN_AUTH_OPEN; ieee->open_wep = 1; + } else if (value & IW_AUTH_ALG_LEAP) { + sec.auth_mode = WLAN_AUTH_LEAP; + ieee->open_wep = 1; } else return -EINVAL; diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index f6c51441fa8..51360910d22 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h @@ -392,8 +392,10 @@ struct ipw2100_notification { #define IPW_WEP104_CIPHER (1<<5) #define IPW_CKIP_CIPHER (1<<6) -#define IPW_AUTH_OPEN 0 -#define IPW_AUTH_SHARED 1 +#define IPW_AUTH_OPEN 0 +#define IPW_AUTH_SHARED 1 +#define IPW_AUTH_LEAP 2 +#define IPW_AUTH_LEAP_CISCO_ID 0x80 struct statistic { int value; -- cgit v1.2.3 From 3173ca0b76879be1fb7af826ae4ce7ee733159ce Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 13:49:01 +0800 Subject: [PATCH] ipw2100: Make iwconfig txpower setting consistent with user input Signed-off-by: Hong Liu Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index b73af778958..80bfc1cf142 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -5107,12 +5107,13 @@ static int ipw2100_set_tx_power(struct ipw2100_priv *priv, u32 tx_power) .host_command_length = 4 }; int err = 0; + u32 tmp = tx_power; if (tx_power != IPW_TX_POWER_DEFAULT) - tx_power = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 / - (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM); + tmp = (tx_power - IPW_TX_POWER_MIN_DBM) * 16 / + (IPW_TX_POWER_MAX_DBM - IPW_TX_POWER_MIN_DBM); - cmd.host_command_parameters[0] = tx_power; + cmd.host_command_parameters[0] = tmp; if (priv->ieee->iw_mode == IW_MODE_ADHOC) err = ipw2100_hw_send_command(priv, &cmd); -- cgit v1.2.3 From be6b3b15b511aededd89d1ebbc7b25d0edd1ccd3 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 13:49:08 +0800 Subject: [PATCH] ipw2100: Add generic geo information This patch fixes a BUG_ON for the latest ieee80211 change. Signed-off-by: Hong Liu Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 80bfc1cf142..b560f5c763e 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -1672,6 +1672,18 @@ static int ipw2100_start_scan(struct ipw2100_priv *priv) return err; } +static const struct ieee80211_geo ipw_geos[] = { + { /* Restricted */ + "---", + .bg_channels = 14, + .bg = {{2412, 1}, {2417, 2}, {2422, 3}, + {2427, 4}, {2432, 5}, {2437, 6}, + {2442, 7}, {2447, 8}, {2452, 9}, + {2457, 10}, {2462, 11}, {2467, 12}, + {2472, 13}, {2484, 14}}, + }, +}; + static int ipw2100_up(struct ipw2100_priv *priv, int deferred) { unsigned long flags; @@ -1727,6 +1739,13 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred) goto exit; } + /* Initialize the geo */ + if (ieee80211_set_geo(priv->ieee, &ipw_geos[0])) { + printk(KERN_WARNING DRV_NAME "Could not set geo\n"); + return 0; + } + priv->ieee->freq_band = IEEE80211_24GHZ_BAND; + lock = LOCK_NONE; if (ipw2100_set_ordinal(priv, IPW_ORD_PERS_DB_LOCK, &lock, &ord_len)) { printk(KERN_ERR DRV_NAME -- cgit v1.2.3 From 8ed55a482e2f044bfb044295ee86ecd5744c9911 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 13:49:20 +0800 Subject: [PATCH] ipw2100: remove white space and better format the code Signed-off-by: James Ketrenos Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index b560f5c763e..8393512da3a 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -3769,7 +3769,7 @@ static ssize_t store_memory(struct device *d, struct device_attribute *attr, struct net_device *dev = priv->net_dev; const char *p = buf; - (void) dev; /* kill unused-var warning for debug-only code */ + (void)dev; /* kill unused-var warning for debug-only code */ if (count < 1) return count; @@ -4089,7 +4089,7 @@ static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, unsigned long val; char *p = buffer; - (void) dev; /* kill unused-var warning for debug-only code */ + (void)dev; /* kill unused-var warning for debug-only code */ IPW_DEBUG_INFO("enter\n"); -- cgit v1.2.3 From 71aa122d8a510b79338e28e2d56326574642d000 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:08:55 +0800 Subject: [PATCH] increase ipw2100 driver version to git-1.1.4 Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 8393512da3a..eb79198ac45 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -167,7 +167,7 @@ that only one external action is invoked at a time. #include "ipw2100.h" -#define IPW2100_VERSION "1.1.3" +#define IPW2100_VERSION "git-1.1.4" #define DRV_NAME "ipw2100" #define DRV_VERSION IPW2100_VERSION -- cgit v1.2.3 From c8fe6679086a983c4c95a441f3246c7aaecab80a Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:36:36 +0800 Subject: [PATCH] ipw2200: Fix indirect SRAM/register 8/16-bit write routines The indirect SRAM/register 8/16-bit write routines are broken for non-dword-aligned destination addresses. Fortunately, these routines are, so far, not used for non-dword-aligned destinations, but here's a patch that fixes them, anyway. The attached patch also adds comments for all direct/indirect I/O routine variations. Signed-off-by: Ben M Cahill Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 86 ++++++++++++++++++++++++++++++++++-------- drivers/net/wireless/ipw2200.h | 13 +++---- 2 files changed, 76 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 2a834deb60e..d7d24b6facf 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -227,12 +227,15 @@ static int snprintk_buf(u8 * output, size_t size, const u8 * data, size_t len) return total; } +/* alias for 32-bit indirect read (for SRAM/reg above 4K), with debug wrapper */ static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg); #define ipw_read_reg32(a, b) _ipw_read_reg32(a, b) +/* alias for 8-bit indirect read (for SRAM/reg above 4K), with debug wrapper */ static u8 _ipw_read_reg8(struct ipw_priv *ipw, u32 reg); #define ipw_read_reg8(a, b) _ipw_read_reg8(a, b) +/* 8-bit indirect write (for SRAM/reg above 4K), with debug wrapper */ static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value); static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c) { @@ -241,6 +244,7 @@ static inline void ipw_write_reg8(struct ipw_priv *a, u32 b, u8 c) _ipw_write_reg8(a, b, c); } +/* 16-bit indirect write (for SRAM/reg above 4K), with debug wrapper */ static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value); static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c) { @@ -249,6 +253,7 @@ static inline void ipw_write_reg16(struct ipw_priv *a, u32 b, u16 c) _ipw_write_reg16(a, b, c); } +/* 32-bit indirect write (for SRAM/reg above 4K), with debug wrapper */ static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value); static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c) { @@ -257,48 +262,76 @@ static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c) _ipw_write_reg32(a, b, c); } +/* 8-bit direct write (low 4K) */ #define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs)) + +/* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ #define ipw_write8(ipw, ofs, val) \ IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ _ipw_write8(ipw, ofs, val) + +/* 16-bit direct write (low 4K) */ #define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs)) + +/* 16-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ #define ipw_write16(ipw, ofs, val) \ IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ _ipw_write16(ipw, ofs, val) + +/* 32-bit direct write (low 4K) */ #define _ipw_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs)) + +/* 32-bit direct write (for low 4K of SRAM/regs), with debug wrapper */ #define ipw_write32(ipw, ofs, val) \ IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ _ipw_write32(ipw, ofs, val) + +/* 8-bit direct read (low 4K) */ #define _ipw_read8(ipw, ofs) readb((ipw)->hw_base + (ofs)) + +/* 8-bit direct read (low 4K), with debug wrapper */ static inline u8 __ipw_read8(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) { IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", f, l, (u32) (ofs)); return _ipw_read8(ipw, ofs); } +/* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */ #define ipw_read8(ipw, ofs) __ipw_read8(__FILE__, __LINE__, ipw, ofs) + +/* 16-bit direct read (low 4K) */ #define _ipw_read16(ipw, ofs) readw((ipw)->hw_base + (ofs)) + +/* 16-bit direct read (low 4K), with debug wrapper */ static inline u16 __ipw_read16(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) { IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", f, l, (u32) (ofs)); return _ipw_read16(ipw, ofs); } +/* alias to 16-bit direct read (low 4K of SRAM/regs), with debug wrapper */ #define ipw_read16(ipw, ofs) __ipw_read16(__FILE__, __LINE__, ipw, ofs) + +/* 32-bit direct read (low 4K) */ #define _ipw_read32(ipw, ofs) readl((ipw)->hw_base + (ofs)) + +/* 32-bit direct read (low 4K), with debug wrapper */ static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) { IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", f, l, (u32) (ofs)); return _ipw_read32(ipw, ofs); } +/* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */ #define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs) + +/* multi-byte read (above 4K), with debug wrapper */ static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int); static inline void __ipw_read_indirect(const char *f, int l, struct ipw_priv *a, u32 b, u8 * c, int d) @@ -308,15 +341,17 @@ static inline void __ipw_read_indirect(const char *f, int l, _ipw_read_indirect(a, b, c, d); } +/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */ #define ipw_read_indirect(a, b, c, d) __ipw_read_indirect(__FILE__, __LINE__, a, b, c, d) +/* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */ static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data, int num); #define ipw_write_indirect(a, b, c, d) \ IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \ _ipw_write_indirect(a, b, c, d) -/* indirect write s */ +/* 32-bit indirect write (above 4K) */ static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value) { IPW_DEBUG_IO(" %p : reg = 0x%8X : value = 0x%8X\n", priv, reg, value); @@ -324,22 +359,30 @@ static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value) _ipw_write32(priv, IPW_INDIRECT_DATA, value); } +/* 8-bit indirect write (above 4K) */ static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value) { + u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ + u32 dif_len = reg - aligned_addr; + IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); - _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK); - _ipw_write8(priv, IPW_INDIRECT_DATA, value); + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); + _ipw_write8(priv, IPW_INDIRECT_DATA + dif_len, value); } +/* 16-bit indirect write (above 4K) */ static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value) { + u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ + u32 dif_len = (reg - aligned_addr) & (~0x1ul); + IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); - _ipw_write32(priv, IPW_INDIRECT_ADDR, reg & IPW_INDIRECT_ADDR_MASK); - _ipw_write16(priv, IPW_INDIRECT_DATA, value); + _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); + _ipw_write16(priv, IPW_INDIRECT_DATA + dif_len, value); } -/* indirect read s */ +/* 8-bit indirect read (above 4K) */ static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg) { u32 word; @@ -349,6 +392,7 @@ static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg) return (word >> ((reg & 0x3) * 8)) & 0xff; } +/* 32-bit indirect read (above 4K) */ static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg) { u32 value; @@ -361,11 +405,12 @@ static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg) return value; } -/* iterative/auto-increment 32 bit reads and writes */ +/* General purpose, no alignment requirement, iterative (multi-byte) read, */ +/* for area above 1st 4K of SRAM/reg space */ static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, int num) { - u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; + u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */ u32 dif_len = addr - aligned_addr; u32 i; @@ -375,7 +420,7 @@ static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, return; } - /* Read the first nibble byte by byte */ + /* Read the first dword (or portion) byte by byte */ if (unlikely(dif_len)) { _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); /* Start reading at aligned_addr + dif_len */ @@ -384,11 +429,12 @@ static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, aligned_addr += 4; } + /* Read all of the middle dwords as dwords, with auto-increment */ _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr); for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) *(u32 *) buf = _ipw_read32(priv, IPW_AUTOINC_DATA); - /* Copy the last nibble */ + /* Read the last dword (or portion) byte by byte */ if (unlikely(num)) { _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); for (i = 0; num > 0; i++, num--) @@ -396,10 +442,12 @@ static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, } } +/* General purpose, no alignment requirement, iterative (multi-byte) write, */ +/* for area above 1st 4K of SRAM/reg space */ static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, int num) { - u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; + u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */ u32 dif_len = addr - aligned_addr; u32 i; @@ -409,20 +457,21 @@ static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, return; } - /* Write the first nibble byte by byte */ + /* Write the first dword (or portion) byte by byte */ if (unlikely(dif_len)) { _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); - /* Start reading at aligned_addr + dif_len */ + /* Start writing at aligned_addr + dif_len */ for (i = dif_len; ((i < 4) && (num > 0)); i++, num--, buf++) _ipw_write8(priv, IPW_INDIRECT_DATA + i, *buf); aligned_addr += 4; } + /* Write all of the middle dwords as dwords, with auto-increment */ _ipw_write32(priv, IPW_AUTOINC_ADDR, aligned_addr); for (; num >= 4; buf += 4, aligned_addr += 4, num -= 4) _ipw_write32(priv, IPW_AUTOINC_DATA, *(u32 *) buf); - /* Copy the last nibble */ + /* Write the last dword (or portion) byte by byte */ if (unlikely(num)) { _ipw_write32(priv, IPW_INDIRECT_ADDR, aligned_addr); for (i = 0; num > 0; i++, num--, buf++) @@ -430,17 +479,21 @@ static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, } } +/* General purpose, no alignment requirement, iterative (multi-byte) write, */ +/* for 1st 4K of SRAM/regs space */ static void ipw_write_direct(struct ipw_priv *priv, u32 addr, void *buf, int num) { memcpy_toio((priv->hw_base + addr), buf, num); } +/* Set bit(s) in low 4K of SRAM/regs */ static inline void ipw_set_bit(struct ipw_priv *priv, u32 reg, u32 mask) { ipw_write32(priv, reg, ipw_read32(priv, reg) | mask); } +/* Clear bit(s) in low 4K of SRAM/regs */ static inline void ipw_clear_bit(struct ipw_priv *priv, u32 reg, u32 mask) { ipw_write32(priv, reg, ipw_read32(priv, reg) & ~mask); @@ -1076,6 +1129,7 @@ static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, static inline u32 ipw_get_event_log_len(struct ipw_priv *priv) { + /* length = 1st dword in log */ return ipw_read_reg32(priv, ipw_read32(priv, IPW_EVENT_LOG)); } @@ -2892,8 +2946,8 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) mdelay(1); /* enable ucode store */ - ipw_write_reg8(priv, DINO_CONTROL_REG, 0x0); - ipw_write_reg8(priv, DINO_CONTROL_REG, DINO_ENABLE_CS); + ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, 0x0); + ipw_write_reg8(priv, IPW_BASEBAND_CONTROL_STATUS, DINO_ENABLE_CS); mdelay(1); /* write ucode */ diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index e2afa76ad3c..44ff76386a8 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1406,13 +1406,6 @@ do { if (ipw_debug_level & (level)) \ * Register bit definitions */ -/* Dino control registers bits */ - -#define DINO_ENABLE_SYSTEM 0x80 -#define DINO_ENABLE_CS 0x40 -#define DINO_RXFIFO_DATA 0x01 -#define DINO_CONTROL_REG 0x00200000 - #define IPW_INTA_RW 0x00000008 #define IPW_INTA_MASK_R 0x0000000C #define IPW_INDIRECT_ADDR 0x00000010 @@ -1459,6 +1452,12 @@ do { if (ipw_debug_level & (level)) \ #define IPW_DOMAIN_0_END 0x1000 #define CLX_MEM_BAR_SIZE 0x1000 + +/* Dino/baseband control registers bits */ + +#define DINO_ENABLE_SYSTEM 0x80 /* 1 = baseband processor on, 0 = reset */ +#define DINO_ENABLE_CS 0x40 /* 1 = enable ucode load */ +#define DINO_RXFIFO_DATA 0x01 /* 1 = data available */ #define IPW_BASEBAND_CONTROL_STATUS 0X00200000 #define IPW_BASEBAND_TX_FIFO_WRITE 0X00200004 #define IPW_BASEBAND_RX_FIFO_READ 0X00200004 -- cgit v1.2.3 From f516dbcd7df76d468be98c343bc22e86ab7207fc Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:36:44 +0800 Subject: [PATCH] ipw2200: Mask out the WEP_KEY command dump from debug log for security reason Signed-off-by: Nick Kralevich Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index d7d24b6facf..b40bfa06372 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1953,7 +1953,14 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) IPW_DEBUG_HC("%s command (#%d) %d bytes: 0x%08X\n", get_cmd_string(cmd->cmd), cmd->cmd, cmd->len, priv->status); - printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len); + +#ifndef DEBUG_CMD_WEP_KEY + if (cmd->cmd == IPW_CMD_WEP_KEY) + IPW_DEBUG_HC("WEP_KEY command masked out for secure.\n"); + else +#endif + printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len); + rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0); if (rc) { -- cgit v1.2.3 From 3e234b4e5768b4f783fc45f20be8c6515b875f17 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:36:52 +0800 Subject: [PATCH] ipw2200: Add LEAP authentication algorithm support Signed-off-by: Hong Liu Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 18 ++++++++++++------ drivers/net/wireless/ipw2200.h | 7 ++++--- 2 files changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index b40bfa06372..67163183122 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -6256,6 +6256,9 @@ static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) } else if (value & IW_AUTH_ALG_OPEN_SYSTEM) { sec.auth_mode = WLAN_AUTH_OPEN; ieee->open_wep = 1; + } else if (value & IW_AUTH_ALG_LEAP) { + sec.auth_mode = WLAN_AUTH_LEAP; + ieee->open_wep = 1; } else return -EINVAL; @@ -7116,19 +7119,22 @@ static int ipw_associate_network(struct ipw_priv *priv, memset(&priv->assoc_request, 0, sizeof(priv->assoc_request)); priv->assoc_request.channel = network->channel; + priv->assoc_request.auth_key = 0; + if ((priv->capability & CAP_PRIVACY_ON) && - (priv->capability & CAP_SHARED_KEY)) { + (priv->ieee->sec.auth_mode == WLAN_AUTH_SHARED_KEY)) { priv->assoc_request.auth_type = AUTH_SHARED_KEY; priv->assoc_request.auth_key = priv->ieee->sec.active_key; - if ((priv->capability & CAP_PRIVACY_ON) && - (priv->ieee->sec.level == SEC_LEVEL_1) && + if ((priv->ieee->sec.level == SEC_LEVEL_1) && !(priv->ieee->host_encrypt || priv->ieee->host_decrypt)) ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); - } else { + + } else if ((priv->capability & CAP_PRIVACY_ON) && + (priv->ieee->sec.auth_mode == WLAN_AUTH_LEAP)) + priv->assoc_request.auth_type = AUTH_LEAP; + else priv->assoc_request.auth_type = AUTH_OPEN; - priv->assoc_request.auth_key = 0; - } if (priv->ieee->wpa_ie_len) { priv->assoc_request.policy_support = 0x02; /* RSN active */ diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 44ff76386a8..5f32834745b 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1657,9 +1657,10 @@ enum { IPW_FW_ERROR_FATAL_ERROR }; -#define AUTH_OPEN 0 -#define AUTH_SHARED_KEY 1 -#define AUTH_IGNORE 3 +#define AUTH_OPEN 0 +#define AUTH_SHARED_KEY 1 +#define AUTH_LEAP 2 +#define AUTH_IGNORE 3 #define HC_ASSOCIATE 0 #define HC_REASSOCIATE 1 -- cgit v1.2.3 From 810dabd466fe70869b66ab64dd326b6153cef645 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:36:59 +0800 Subject: [PATCH] ipw2200: Bluetooth coexistence support I've added a new module param "bt_coexist" which defaults to OFF. This does not seem to fix the firmware restarts, but it does do "the right thing" and disables something that we were enabling by default: signaling the Bluetooth h/w which channel we're on (whether or not the BT h/w was out there). Signed-off-by: Ben M Cahill Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 20 +++++++++++++++++++- drivers/net/wireless/ipw2200.h | 35 +++++++++++++++++++++-------------- 2 files changed, 40 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 67163183122..e6a23c2be1a 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -55,6 +55,7 @@ static int associate = 1; static int auto_create = 1; static int led = 0; static int disable = 0; +static int bt_coexist = 0; static int hwcrypto = 1; static const char ipw_modes[] = { 'a', 'b', 'g', '?' @@ -9656,7 +9657,7 @@ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev) static void init_sys_config(struct ipw_sys_config *sys_config) { memset(sys_config, 0, sizeof(struct ipw_sys_config)); - sys_config->bt_coexistence = 1; /* We may need to look into prvStaBtConfig */ + sys_config->bt_coexistence = 0; sys_config->answer_broadcast_ssid_probe = 0; sys_config->accept_all_data_frames = 0; sys_config->accept_non_directed_frames = 1; @@ -10362,6 +10363,20 @@ static int ipw_config(struct ipw_priv *priv) /* set basic system config settings */ init_sys_config(&priv->sys_config); + + /* Support Bluetooth if we have BT h/w on board, and user wants to. + * Does not support BT priority yet (don't abort or defer our Tx) */ + if (bt_coexist) { + unsigned char bt_caps = priv->eeprom[EEPROM_SKU_CAPABILITY]; + + if (bt_caps & EEPROM_SKU_CAP_BT_CHANNEL_SIG) + priv->sys_config.bt_coexistence + |= CFG_BT_COEXISTENCE_SIGNAL_CHNL; + if (bt_caps & EEPROM_SKU_CAP_BT_OOB) + priv->sys_config.bt_coexistence + |= CFG_BT_COEXISTENCE_OOB; + } + if (priv->ieee->iw_mode == IW_MODE_ADHOC) priv->sys_config.answer_broadcast_ssid_probe = 1; else @@ -11351,6 +11366,9 @@ module_param(mode, int, 0444); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS)"); #endif +module_param(bt_coexist, int, 0444); +MODULE_PARM_DESC(bt_coexist, "enable bluetooth coexistence (default off)"); + module_param(hwcrypto, int, 0444); MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default on)"); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 5f32834745b..d6d7d9db046 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1566,13 +1566,18 @@ do { if (ipw_debug_level & (level)) \ #define EEPROM_BSS_CHANNELS_BG (GET_EEPROM_ADDR(0x2c,LSB)) /* 2 bytes */ #define EEPROM_HW_VERSION (GET_EEPROM_ADDR(0x72,LSB)) /* 2 bytes */ -/* NIC type as found in the one byte EEPROM_NIC_TYPE offset*/ +/* NIC type as found in the one byte EEPROM_NIC_TYPE offset */ #define EEPROM_NIC_TYPE_0 0 #define EEPROM_NIC_TYPE_1 1 #define EEPROM_NIC_TYPE_2 2 #define EEPROM_NIC_TYPE_3 3 #define EEPROM_NIC_TYPE_4 4 +/* Bluetooth Coexistence capabilities as found in EEPROM_SKU_CAPABILITY */ +#define EEPROM_SKU_CAP_BT_CHANNEL_SIG 0x01 /* we can tell BT our channel # */ +#define EEPROM_SKU_CAP_BT_PRIORITY 0x02 /* BT can take priority over us */ +#define EEPROM_SKU_CAP_BT_OOB 0x04 /* we can signal BT out-of-band */ + #define FW_MEM_REG_LOWER_BOUND 0x00300000 #define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40) #define IPW_EVENT_REG (FW_MEM_REG_LOWER_BOUND + 0x04) @@ -1869,21 +1874,23 @@ struct ipw_cmd_log { struct host_cmd cmd; }; -#define CFG_BT_COEXISTENCE_MIN 0x00 -#define CFG_BT_COEXISTENCE_DEFER 0x02 -#define CFG_BT_COEXISTENCE_KILL 0x04 -#define CFG_BT_COEXISTENCE_WME_OVER_BT 0x08 -#define CFG_BT_COEXISTENCE_OOB 0x10 -#define CFG_BT_COEXISTENCE_MAX 0xFF -#define CFG_BT_COEXISTENCE_DEF 0x80 /* read Bt from EEPROM */ - -#define CFG_CTS_TO_ITSELF_ENABLED_MIN 0x0 -#define CFG_CTS_TO_ITSELF_ENABLED_MAX 0x1 +/* SysConfig command parameters ... */ +/* bt_coexistence param */ +#define CFG_BT_COEXISTENCE_SIGNAL_CHNL 0x01 /* tell BT our chnl # */ +#define CFG_BT_COEXISTENCE_DEFER 0x02 /* defer our Tx if BT traffic */ +#define CFG_BT_COEXISTENCE_KILL 0x04 /* kill our Tx if BT traffic */ +#define CFG_BT_COEXISTENCE_WME_OVER_BT 0x08 /* multimedia extensions */ +#define CFG_BT_COEXISTENCE_OOB 0x10 /* signal BT via out-of-band */ + +/* clear-to-send to self param */ +#define CFG_CTS_TO_ITSELF_ENABLED_MIN 0x00 +#define CFG_CTS_TO_ITSELF_ENABLED_MAX 0x01 #define CFG_CTS_TO_ITSELF_ENABLED_DEF CFG_CTS_TO_ITSELF_ENABLED_MIN -#define CFG_SYS_ANTENNA_BOTH 0x000 -#define CFG_SYS_ANTENNA_A 0x001 -#define CFG_SYS_ANTENNA_B 0x003 +/* Antenna diversity param (h/w can select best antenna, based on signal) */ +#define CFG_SYS_ANTENNA_BOTH 0x00 /* NIC selects best antenna */ +#define CFG_SYS_ANTENNA_A 0x01 /* force antenna A */ +#define CFG_SYS_ANTENNA_B 0x03 /* force antenna B */ /* * The definitions below were lifted off the ipw2100 driver, which only -- cgit v1.2.3 From c7b6a6744c3eb878e08ef992d57cd01eed457810 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:37:05 +0800 Subject: [PATCH] ipw2200: use jiffies_to_msec() wherever possible This substitutes Linux jiffies_to_msec() wherever there is a computation for determining milliseconds from jiffies, following lead from ieee80211 code. And it does a little cleanup. "it's" == "it is" ... "its" == possessive "it". Indulge me. ;-) Signed-off-by: Cahill, Ben M Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 30 ++++++++++++++++-------------- drivers/net/wireless/ipw2200.h | 1 + 2 files changed, 17 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index e6a23c2be1a..d3aa59d0461 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -2112,8 +2112,8 @@ static void ipw_scan_check(void *data) struct ipw_priv *priv = data; if (priv->status & (STATUS_SCANNING | STATUS_SCAN_ABORTING)) { IPW_DEBUG_SCAN("Scan completion watchdog resetting " - "adapter (%dms).\n", - IPW_SCAN_CHECK_WATCHDOG / 100); + "adapter after (%dms).\n", + jiffies_to_msecs(IPW_SCAN_CHECK_WATCHDOG)); queue_work(priv->workqueue, &priv->adapter_restart); } } @@ -2518,7 +2518,7 @@ static void ipw_eeprom_init_sram(struct ipw_priv *priv) /* If the data looks correct, then copy it to our private copy. Otherwise let the firmware know to perform the operation - on it's own + on its own. */ if ((priv->eeprom + EEPROM_VERSION) != 0) { IPW_DEBUG_INFO("Writing EEPROM data into SRAM\n"); @@ -2836,6 +2836,7 @@ static inline int ipw_alive(struct ipw_priv *priv) return ipw_read32(priv, 0x90) == 0xd55555d5; } +/* timeout in msec, attempted in 10-msec quanta */ static int ipw_poll_bit(struct ipw_priv *priv, u32 addr, u32 mask, int timeout) { @@ -2864,10 +2865,11 @@ static int ipw_stop_master(struct ipw_priv *priv) /* stop master. typical delay - 0 */ ipw_set_bit(priv, IPW_RESET_REG, IPW_RESET_REG_STOP_MASTER); + /* timeout is in msec, polled in 10-msec quanta */ rc = ipw_poll_bit(priv, IPW_RESET_REG, IPW_RESET_REG_MASTER_DISABLED, 100); if (rc < 0) { - IPW_ERROR("stop master failed in 10ms\n"); + IPW_ERROR("wait for stop master failed after 100ms\n"); return -1; } @@ -3100,7 +3102,7 @@ static int ipw_stop_nic(struct ipw_priv *priv) rc = ipw_poll_bit(priv, IPW_RESET_REG, IPW_RESET_REG_MASTER_DISABLED, 500); if (rc < 0) { - IPW_ERROR("wait for reg master disabled failed\n"); + IPW_ERROR("wait for reg master disabled failed after 500ms\n"); return rc; } @@ -3362,7 +3364,7 @@ static int ipw_load(struct ipw_priv *priv) /* kick start the device */ ipw_start_nic(priv); - /* wait for the device to finish it's initial startup sequence */ + /* wait for the device to finish its initial startup sequence */ rc = ipw_poll_bit(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500); if (rc < 0) { @@ -3426,7 +3428,7 @@ static int ipw_load(struct ipw_priv *priv) rc = ipw_poll_bit(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE, 500); if (rc < 0) { - IPW_ERROR("device failed to start after 500ms\n"); + IPW_ERROR("device failed to start within 500ms\n"); goto error; } IPW_DEBUG_INFO("device response after %dms\n", rc); @@ -4981,7 +4983,7 @@ static void ipw_bg_rx_queue_replenish(void *data) } /* Assumes that the skb field of the buffers in 'pool' is kept accurate. - * If an SKB has been detached, the POOL needs to have it's SKB set to NULL + * If an SKB has been detached, the POOL needs to have its SKB set to NULL * This free routine walks the list of POOL entries and if SKB is set to * non NULL it is unmapped and freed */ @@ -5321,10 +5323,10 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { IPW_DEBUG_MERGE("Network '%s (" MAC_FMT ")' excluded " - "because of age: %lums.\n", + "because of age: %ums.\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), - 1000 * (jiffies - network->last_scanned) / HZ); + jiffies_to_msecs(jiffies - network->last_scanned)); return 0; } @@ -5531,11 +5533,11 @@ static int ipw_best_network(struct ipw_priv *priv, if (network->last_associate && time_after(network->last_associate + (HZ * 3UL), jiffies)) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " - "because of storming (%lus since last " + "because of storming (%ums since last " "assoc attempt).\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), - (jiffies - network->last_associate) / HZ); + jiffies_to_msecs(jiffies - network->last_associate)); return 0; } @@ -5543,10 +5545,10 @@ static int ipw_best_network(struct ipw_priv *priv, if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " - "because of age: %lums.\n", + "because of age: %ums.\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), - 1000 * (jiffies - network->last_scanned) / HZ); + jiffies_to_msecs(jiffies - network->last_scanned)); return 0; } diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index d6d7d9db046..04a0c26cab8 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -46,6 +46,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From ede6111cae6a83fbb0b6b621b4333d1a3983c089 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:37:10 +0800 Subject: [PATCH] ipw2200: Make LED blinking frequency independent of HZ Signed-off-by: Clemens Buchacher . Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index d3aa59d0461..37cd71cd114 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -776,9 +776,9 @@ static u32 ipw_register_toggle(u32 reg) * - On radio OFF, turn off any LEDs started during radio on * */ -#define LD_TIME_LINK_ON 300 -#define LD_TIME_LINK_OFF 2700 -#define LD_TIME_ACT_ON 250 +#define LD_TIME_LINK_ON msecs_to_jiffies(300) +#define LD_TIME_LINK_OFF msecs_to_jiffies(2700) +#define LD_TIME_ACT_ON msecs_to_jiffies(250) static void ipw_led_link_on(struct ipw_priv *priv) { -- cgit v1.2.3 From 4bfdb91dcff0dd4b70922de263ccffffb8fb1d16 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:37:16 +0800 Subject: [PATCH] ipw2200: add module parameter to enable/disable roaming Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 37cd71cd114..624f2950049 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -57,6 +57,7 @@ static int led = 0; static int disable = 0; static int bt_coexist = 0; static int hwcrypto = 1; +static int roaming = 1; static const char ipw_modes[] = { 'a', 'b', 'g', '?' }; @@ -4187,8 +4188,9 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, return; } - if (missed_count > priv->roaming_threshold && - missed_count <= priv->disassociate_threshold) { + if (roaming && + (missed_count > priv->roaming_threshold && + missed_count <= priv->disassociate_threshold)) { /* If we are not already roaming, set the ROAM * bit in the status and kick off a scan. * This can happen several times before we reach @@ -4216,7 +4218,6 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, } IPW_DEBUG_NOTIF("Missed beacon: %d\n", missed_count); - } /** @@ -11378,5 +11379,8 @@ module_param(cmdlog, int, 0444); MODULE_PARM_DESC(cmdlog, "allocate a ring buffer for logging firmware commands"); +module_param(roaming, int, 0444); +MODULE_PARM_DESC(roaming, "enable roaming support (default on)"); + module_exit(ipw_exit); module_init(ipw_init); -- cgit v1.2.3 From 397ae121ee0116d3b4125d621f0ef528d1d52580 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:37:22 +0800 Subject: [PATCH] ipw2200: Scale firmware loading watchdog with the firmware size I can't really help with why restarts happen, but the following patch greatly increases the likelihood that a firmware reload will succeed afterward on my thinkpad. It addresses two issues. First, sysfs module loading and hotplug are asynchronous, and as such file operations on the "loading" and "data" files are racy when you load 2 firmwares in quick succession. Second, the timeout for DMAing the firmware needs to scale with the size of the firmware being loaded. That is, the watchdog needs to be on throughput, not on time alone. I no longer get the firmware load errors, though this is at best a hacky workaround for a racy interface. (Obviously, this does nothing to address the fatal errors in firmware which cause reloads; it just causes the initial loading and the reloads to work more often.) Signed-off-by: Peter Jones Signed-off-by: Ben M Cahill Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 114 +++++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 51 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 624f2950049..c42eb54f379 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -2772,22 +2772,25 @@ static int ipw_fw_dma_add_buffer(struct ipw_priv *priv, static int ipw_fw_dma_wait(struct ipw_priv *priv) { - u32 current_index = 0; + u32 current_index = 0, previous_index; u32 watchdog = 0; IPW_DEBUG_FW(">> : \n"); current_index = ipw_fw_dma_command_block_index(priv); - IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%8X\n", + IPW_DEBUG_FW_INFO("sram_desc.last_cb_index:0x%08X\n", (int)priv->sram_desc.last_cb_index); while (current_index < priv->sram_desc.last_cb_index) { udelay(50); + previous_index = current_index; current_index = ipw_fw_dma_command_block_index(priv); - watchdog++; - - if (watchdog > 400) { + if (previous_index < current_index) { + watchdog = 0; + continue; + } + if (++watchdog > 400) { IPW_DEBUG_FW_INFO("Timeout\n"); ipw_fw_dma_dump_command_block(priv); ipw_fw_dma_abort(priv); @@ -3276,55 +3279,31 @@ static int ipw_load(struct ipw_priv *priv) const struct firmware *firmware = NULL; const struct firmware *ucode = NULL; #endif + char *ucode_name; + char *fw_name; int rc = 0, retries = 3; -#ifdef CONFIG_PM - if (!fw_loaded) { -#endif - rc = ipw_get_fw(priv, &bootfw, IPW_FW_NAME("boot")); - if (rc) - goto error; - - switch (priv->ieee->iw_mode) { - case IW_MODE_ADHOC: - rc = ipw_get_fw(priv, &ucode, - IPW_FW_NAME("ibss_ucode")); - if (rc) - goto error; - - rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("ibss")); - break; - + switch (priv->ieee->iw_mode) { + case IW_MODE_ADHOC: + ucode_name = IPW_FW_NAME("ibss_ucode"); + fw_name = IPW_FW_NAME("ibss"); + break; #ifdef CONFIG_IPW2200_MONITOR - case IW_MODE_MONITOR: - rc = ipw_get_fw(priv, &ucode, - IPW_FW_NAME("sniffer_ucode")); - if (rc) - goto error; - - rc = ipw_get_fw(priv, &firmware, - IPW_FW_NAME("sniffer")); - break; + case IW_MODE_MONITOR: + ucode_name = IPW_FW_NAME("sniffer_ucode"); + fw_name = IPW_FW_NAME("sniffer"); + break; #endif - case IW_MODE_INFRA: - rc = ipw_get_fw(priv, &ucode, IPW_FW_NAME("bss_ucode")); - if (rc) - goto error; - - rc = ipw_get_fw(priv, &firmware, IPW_FW_NAME("bss")); - break; - - default: - rc = -EINVAL; - } - - if (rc) - goto error; - -#ifdef CONFIG_PM - fw_loaded = 1; + case IW_MODE_INFRA: + ucode_name = IPW_FW_NAME("bss_ucode"); + fw_name = IPW_FW_NAME("bss"); + break; + default: + rc = -EINVAL; } -#endif + + if (rc < 0) + goto error; if (!priv->rxq) priv->rxq = ipw_rx_queue_alloc(priv); @@ -3346,7 +3325,7 @@ static int ipw_load(struct ipw_priv *priv) ipw_stop_nic(priv); rc = ipw_reset_nic(priv); - if (rc) { + if (rc < 0) { IPW_ERROR("Unable to reset NIC\n"); goto error; } @@ -3354,6 +3333,15 @@ static int ipw_load(struct ipw_priv *priv) ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND, IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND); +#ifdef CONFIG_PM + if (!fw_loaded) { +#endif + rc = ipw_get_fw(priv, &bootfw, IPW_FW_NAME("boot")); + if (rc < 0) + goto error; +#ifdef CONFIG_PM + } +#endif /* DMA the initial boot firmware into the device */ rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header), bootfw->size - sizeof(struct fw_header)); @@ -3377,6 +3365,16 @@ static int ipw_load(struct ipw_priv *priv) /* ack fw init done interrupt */ ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE); +#ifdef CONFIG_PM + if (!fw_loaded) { +#endif + rc = ipw_get_fw(priv, &ucode, ucode_name); + if (rc < 0) + goto error; +#ifdef CONFIG_PM + } +#endif + /* DMA the ucode into the device */ rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header), ucode->size - sizeof(struct fw_header)); @@ -3388,6 +3386,16 @@ static int ipw_load(struct ipw_priv *priv) /* stop nic */ ipw_stop_nic(priv); +#ifdef CONFIG_PM + if (!fw_loaded) { +#endif + rc = ipw_get_fw(priv, &firmware, fw_name); + if (rc < 0) + goto error; +#ifdef CONFIG_PM + } +#endif + /* DMA bss firmware into the device */ rc = ipw_load_firmware(priv, firmware->data + sizeof(struct fw_header), @@ -3397,10 +3405,14 @@ static int ipw_load(struct ipw_priv *priv) goto error; } +#ifdef CONFIG_PM + fw_loaded = 1; +#endif + ipw_write32(priv, IPW_EEPROM_LOAD_DISABLE, 0); rc = ipw_queue_reset(priv); - if (rc) { + if (rc < 0) { IPW_ERROR("Unable to initialize queues\n"); goto error; } -- cgit v1.2.3 From 0a7bcf261ea584c87a9cee4523023fa74168de4a Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:37:28 +0800 Subject: [PATCH] ipw2200: stack reduction Checking the stack usage of my kernel, showed that ipw2200 had a few bad offenders. This is on i386 32-bit: 0x00002876 ipw_send_associate: 544 0x000028ee ipw_send_associate: 544 0x000027dc ipw_send_scan_request_ext: 520 0x00002864 ipw_set_sensitivity: 520 0x00005eac ipw_set_rsn_capa: 520 The reason is the host_cmd structure is large (500 bytes). All other functions currently using ipw_send_cmd() suffer from the same problem. This patch introduces ipw_send_cmd_simple() for commands with no data transfer, and ipw_send_cmd_pdu() for commands with a data payload and makes the payload a pointer to the buffer passed in from the caller. As an added bonus, the diffstat looks like this: ipw2200.c | 260 +++++++++++++++++++++----------------------------------------- ipw2200.h | 2 2 files changed, 92 insertions(+), 170 deletions(-) and it shrinks the module a lot as well: Before: text data bss dec hex filename 75177 2472 44 77693 12f7d drivers/net/wireless/ipw2200.ko After: text data bss dec hex filename 61363 2488 44 63895 f997 drivers/net/wireless/ipw2200.ko So about a ~18% reduction in module size. Signed-off-by: Jens Axboe Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 253 +++++++++++++++-------------------------- drivers/net/wireless/ipw2200.h | 2 +- 2 files changed, 91 insertions(+), 164 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index c42eb54f379..2fe1e048328 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1928,7 +1928,8 @@ static char *get_cmd_string(u8 cmd) } #define HOST_COMPLETE_TIMEOUT HZ -static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) + +static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) { int rc = 0; unsigned long flags; @@ -1964,7 +1965,7 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len); - rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0); + rc = ipw_queue_tx_hcmd(priv, cmd->cmd, cmd->param, cmd->len, 0); if (rc) { priv->status &= ~STATUS_HCMD_ACTIVE; IPW_ERROR("Failed to send %s: Reason %d\n", @@ -1999,7 +2000,7 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) goto exit; } - exit: +exit: if (priv->cmdlog) { priv->cmdlog[priv->cmdlog_pos++].retcode = rc; priv->cmdlog_pos %= priv->cmdlog_len; @@ -2007,61 +2008,62 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) return rc; } -static int ipw_send_host_complete(struct ipw_priv *priv) +static int ipw_send_cmd_simple(struct ipw_priv *priv, u8 command) +{ + struct host_cmd cmd = { + .cmd = command, + }; + + return __ipw_send_cmd(priv, &cmd); +} + +static int ipw_send_cmd_pdu(struct ipw_priv *priv, u8 command, u8 len, + void *data) { struct host_cmd cmd = { - .cmd = IPW_CMD_HOST_COMPLETE, - .len = 0 + .cmd = command, + .len = len, + .param = data, }; + return __ipw_send_cmd(priv, &cmd); +} + +static int ipw_send_host_complete(struct ipw_priv *priv) +{ if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_simple(priv, IPW_CMD_HOST_COMPLETE); } static int ipw_send_system_config(struct ipw_priv *priv, struct ipw_sys_config *config) { - struct host_cmd cmd = { - .cmd = IPW_CMD_SYSTEM_CONFIG, - .len = sizeof(*config) - }; - if (!priv || !config) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(cmd.param, config, sizeof(*config)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG, sizeof(*config), + config); } static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) { - struct host_cmd cmd = { - .cmd = IPW_CMD_SSID, - .len = min(len, IW_ESSID_MAX_SIZE) - }; - if (!priv || !ssid) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(cmd.param, ssid, cmd.len); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_SSID, min(len, IW_ESSID_MAX_SIZE), + ssid); } static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) { - struct host_cmd cmd = { - .cmd = IPW_CMD_ADAPTER_ADDRESS, - .len = ETH_ALEN - }; - if (!priv || !mac) { IPW_ERROR("Invalid args\n"); return -1; @@ -2070,8 +2072,8 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n", priv->net_dev->name, MAC_ARG(mac)); - memcpy(cmd.param, mac, ETH_ALEN); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, + mac); } /* @@ -2130,51 +2132,40 @@ static void ipw_bg_scan_check(void *data) static int ipw_send_scan_request_ext(struct ipw_priv *priv, struct ipw_scan_request_ext *request) { - struct host_cmd cmd = { - .cmd = IPW_CMD_SCAN_REQUEST_EXT, - .len = sizeof(*request) - }; - - memcpy(cmd.param, request, sizeof(*request)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_SCAN_REQUEST_EXT, + sizeof(*request), request); } static int ipw_send_scan_abort(struct ipw_priv *priv) { - struct host_cmd cmd = { - .cmd = IPW_CMD_SCAN_ABORT, - .len = 0 - }; - if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_simple(priv, IPW_CMD_SCAN_ABORT); } static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens) { - struct host_cmd cmd = { - .cmd = IPW_CMD_SENSITIVITY_CALIB, - .len = sizeof(struct ipw_sensitivity_calib) + struct ipw_sensitivity_calib calib = { + .beacon_rssi_raw = sens, }; - struct ipw_sensitivity_calib *calib = (struct ipw_sensitivity_calib *) - &cmd.param; - calib->beacon_rssi_raw = sens; - return ipw_send_cmd(priv, &cmd); + + return ipw_send_cmd_pdu(priv, IPW_CMD_SENSITIVITY_CALIB, sizeof(calib), + &calib); } static int ipw_send_associate(struct ipw_priv *priv, struct ipw_associate *associate) { - struct host_cmd cmd = { - .cmd = IPW_CMD_ASSOCIATE, - .len = sizeof(*associate) - }; - struct ipw_associate tmp_associate; + + if (!priv || !associate) { + IPW_ERROR("Invalid args\n"); + return -1; + } + memcpy(&tmp_associate, associate, sizeof(*associate)); tmp_associate.policy_support = cpu_to_le16(tmp_associate.policy_support); @@ -2187,80 +2178,56 @@ static int ipw_send_associate(struct ipw_priv *priv, cpu_to_le16(tmp_associate.beacon_interval); tmp_associate.atim_window = cpu_to_le16(tmp_associate.atim_window); - if (!priv || !associate) { - IPW_ERROR("Invalid args\n"); - return -1; - } - - memcpy(cmd.param, &tmp_associate, sizeof(*associate)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(tmp_associate), + &tmp_associate); } static int ipw_send_supported_rates(struct ipw_priv *priv, struct ipw_supported_rates *rates) { - struct host_cmd cmd = { - .cmd = IPW_CMD_SUPPORTED_RATES, - .len = sizeof(*rates) - }; - if (!priv || !rates) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(cmd.param, rates, sizeof(*rates)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_SUPPORTED_RATES, sizeof(*rates), + rates); } static int ipw_set_random_seed(struct ipw_priv *priv) { - struct host_cmd cmd = { - .cmd = IPW_CMD_SEED_NUMBER, - .len = sizeof(u32) - }; + u32 val; if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } - get_random_bytes(&cmd.param, sizeof(u32)); + get_random_bytes(&val, sizeof(val)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_SEED_NUMBER, sizeof(val), &val); } static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off) { - struct host_cmd cmd = { - .cmd = IPW_CMD_CARD_DISABLE, - .len = sizeof(u32) - }; - if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } - *((u32 *) & cmd.param) = phy_off; - - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(phy_off), + &phy_off); } static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) { - struct host_cmd cmd = { - .cmd = IPW_CMD_TX_POWER, - .len = sizeof(*power) - }; - if (!priv || !power) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(cmd.param, power, sizeof(*power)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_TX_POWER, sizeof(*power), + power); } static int ipw_set_tx_power(struct ipw_priv *priv) @@ -2312,18 +2279,14 @@ static int ipw_send_rts_threshold(struct ipw_priv *priv, u16 rts) struct ipw_rts_threshold rts_threshold = { .rts_threshold = rts, }; - struct host_cmd cmd = { - .cmd = IPW_CMD_RTS_THRESHOLD, - .len = sizeof(rts_threshold) - }; if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(cmd.param, &rts_threshold, sizeof(rts_threshold)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_RTS_THRESHOLD, + sizeof(rts_threshold), &rts_threshold); } static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag) @@ -2331,27 +2294,19 @@ static int ipw_send_frag_threshold(struct ipw_priv *priv, u16 frag) struct ipw_frag_threshold frag_threshold = { .frag_threshold = frag, }; - struct host_cmd cmd = { - .cmd = IPW_CMD_FRAG_THRESHOLD, - .len = sizeof(frag_threshold) - }; if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(cmd.param, &frag_threshold, sizeof(frag_threshold)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_FRAG_THRESHOLD, + sizeof(frag_threshold), &frag_threshold); } static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) { - struct host_cmd cmd = { - .cmd = IPW_CMD_POWER_MODE, - .len = sizeof(u32) - }; - u32 *param = (u32 *) (&cmd.param); + u32 param; if (!priv) { IPW_ERROR("Invalid args\n"); @@ -2362,17 +2317,18 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) * level */ switch (mode) { case IPW_POWER_BATTERY: - *param = IPW_POWER_INDEX_3; + param = IPW_POWER_INDEX_3; break; case IPW_POWER_AC: - *param = IPW_POWER_MODE_CAM; + param = IPW_POWER_MODE_CAM; break; default: - *param = mode; + param = mode; break; } - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param), + ¶m); } static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit) @@ -2381,18 +2337,14 @@ static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit) .short_retry_limit = slimit, .long_retry_limit = llimit }; - struct host_cmd cmd = { - .cmd = IPW_CMD_RETRY_LIMIT, - .len = sizeof(retry_limit) - }; if (!priv) { IPW_ERROR("Invalid args\n"); return -1; } - memcpy(cmd.param, &retry_limit, sizeof(retry_limit)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_RETRY_LIMIT, sizeof(retry_limit), + &retry_limit); } /* @@ -5750,54 +5702,44 @@ static void ipw_adhoc_create(struct ipw_priv *priv, static void ipw_send_tgi_tx_key(struct ipw_priv *priv, int type, int index) { - struct ipw_tgi_tx_key *key; - struct host_cmd cmd = { - .cmd = IPW_CMD_TGI_TX_KEY, - .len = sizeof(*key) - }; + struct ipw_tgi_tx_key key; if (!(priv->ieee->sec.flags & (1 << index))) return; - key = (struct ipw_tgi_tx_key *)&cmd.param; - key->key_id = index; - memcpy(key->key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH); - key->security_type = type; - key->station_index = 0; /* always 0 for BSS */ - key->flags = 0; + key.key_id = index; + memcpy(key.key, priv->ieee->sec.keys[index], SCM_TEMPORAL_KEY_LENGTH); + key.security_type = type; + key.station_index = 0; /* always 0 for BSS */ + key.flags = 0; /* 0 for new key; previous value of counter (after fatal error) */ - key->tx_counter[0] = 0; - key->tx_counter[1] = 0; + key.tx_counter[0] = 0; + key.tx_counter[1] = 0; - ipw_send_cmd(priv, &cmd); + ipw_send_cmd_pdu(priv, IPW_CMD_TGI_TX_KEY, sizeof(key), &key); } static void ipw_send_wep_keys(struct ipw_priv *priv, int type) { - struct ipw_wep_key *key; + struct ipw_wep_key key; int i; - struct host_cmd cmd = { - .cmd = IPW_CMD_WEP_KEY, - .len = sizeof(*key) - }; - key = (struct ipw_wep_key *)&cmd.param; - key->cmd_id = DINO_CMD_WEP_KEY; - key->seq_num = 0; + key.cmd_id = DINO_CMD_WEP_KEY; + key.seq_num = 0; /* Note: AES keys cannot be set for multiple times. * Only set it at the first time. */ for (i = 0; i < 4; i++) { - key->key_index = i | type; + key.key_index = i | type; if (!(priv->ieee->sec.flags & (1 << i))) { - key->key_size = 0; + key.key_size = 0; continue; } - key->key_size = priv->ieee->sec.key_sizes[i]; - memcpy(key->key, priv->ieee->sec.keys[i], key->key_size); + key.key_size = priv->ieee->sec.key_sizes[i]; + memcpy(key.key, priv->ieee->sec.keys[i], key.key_size); - ipw_send_cmd(priv, &cmd); + ipw_send_cmd_pdu(priv, IPW_CMD_WEP_KEY, sizeof(key), &key); } } @@ -6298,15 +6240,10 @@ static void ipw_wpa_assoc_frame(struct ipw_priv *priv, char *wpa_ie, static int ipw_set_rsn_capa(struct ipw_priv *priv, char *capabilities, int length) { - struct host_cmd cmd = { - .cmd = IPW_CMD_RSN_CAPABILITIES, - .len = length, - }; - IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n"); - memcpy(cmd.param, capabilities, length); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_RSN_CAPABILITIES, length, + capabilities); } /* @@ -7093,25 +7030,15 @@ static int ipw_handle_assoc_response(struct net_device *dev, static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters *qos_param) { - struct host_cmd cmd = { - .cmd = IPW_CMD_QOS_PARAMETERS, - .len = (sizeof(struct ieee80211_qos_parameters) * 3) - }; - - memcpy(cmd.param, qos_param, sizeof(*qos_param) * 3); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_QOS_PARAMETERS, qos_param, + sizeof(*qos_param) * 3); } static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element *qos_param) { - struct host_cmd cmd = { - .cmd = IPW_CMD_WME_INFO, - .len = sizeof(*qos_param) - }; - - memcpy(cmd.param, qos_param, sizeof(*qos_param)); - return ipw_send_cmd(priv, &cmd); + return ipw_send_cmd_pdu(priv, IPW_CMD_WME_INFO, qos_param, + sizeof(*qos_param)); } #endif /* CONFIG_IPW_QOS */ diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 04a0c26cab8..c09888b1f1f 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1866,7 +1866,7 @@ struct host_cmd { u8 cmd; u8 len; u16 reserved; - u32 param[TFD_CMD_IMMEDIATE_PAYLOAD_LENGTH]; + u32 *param; } __attribute__ ((packed)); struct ipw_cmd_log { -- cgit v1.2.3 From 4e22699fa264b88084210ceaa63747b8352bd517 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:37:36 +0800 Subject: [PATCH] ipw2200: Fix qos_cmd param switch bug The patch fixes a couple of errors regarding QoS, which results in compile warnings and malfunction of the driver. Signed-off-by: Henrik Brix Andersen Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 2fe1e048328..072746c07a9 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7030,15 +7030,15 @@ static int ipw_handle_assoc_response(struct net_device *dev, static int ipw_send_qos_params_command(struct ipw_priv *priv, struct ieee80211_qos_parameters *qos_param) { - return ipw_send_cmd_pdu(priv, IPW_CMD_QOS_PARAMETERS, qos_param, - sizeof(*qos_param) * 3); + return ipw_send_cmd_pdu(priv, IPW_CMD_QOS_PARAMETERS, + sizeof(*qos_param) * 3, qos_param); } static int ipw_send_qos_info_command(struct ipw_priv *priv, struct ieee80211_qos_information_element *qos_param) { - return ipw_send_cmd_pdu(priv, IPW_CMD_WME_INFO, qos_param, - sizeof(*qos_param)); + return ipw_send_cmd_pdu(priv, IPW_CMD_WME_INFO, sizeof(*qos_param), + qos_param); } #endif /* CONFIG_IPW_QOS */ -- cgit v1.2.3 From 7c97eb3f1dd09548fe7167e684da4fc94580aceb Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:37:47 +0800 Subject: [PATCH] ipw2200: increase ipw2200 driver version increase ipw2200 driver version to git-1.0.10 Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 072746c07a9..7d61257249a 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -33,7 +33,7 @@ #include "ipw2200.h" #include -#define IPW2200_VERSION "git-1.0.8" +#define IPW2200_VERSION "git-1.0.10" #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 2003-2005 Intel Corporation" #define DRV_VERSION IPW2200_VERSION -- cgit v1.2.3 From 2638bc394195f27801d1c184c4358ce25599146b Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:37:52 +0800 Subject: [PATCH] ipw2200: remove white space and better format the code Signed-off-by: James Ketrenos Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 62 ++++++++++++++++++------------------------ drivers/net/wireless/ipw2200.h | 29 ++++++++++---------- 2 files changed, 41 insertions(+), 50 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 7d61257249a..f793cd8f8d7 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -272,7 +272,6 @@ static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c) IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ _ipw_write8(ipw, ofs, val) - /* 16-bit direct write (low 4K) */ #define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs)) @@ -281,7 +280,6 @@ static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c) IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ _ipw_write16(ipw, ofs, val) - /* 32-bit direct write (low 4K) */ #define _ipw_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs)) @@ -290,7 +288,6 @@ static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c) IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \ _ipw_write32(ipw, ofs, val) - /* 8-bit direct read (low 4K) */ #define _ipw_read8(ipw, ofs) readb((ipw)->hw_base + (ofs)) @@ -304,7 +301,6 @@ static inline u8 __ipw_read8(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) /* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */ #define ipw_read8(ipw, ofs) __ipw_read8(__FILE__, __LINE__, ipw, ofs) - /* 16-bit direct read (low 4K) */ #define _ipw_read16(ipw, ofs) readw((ipw)->hw_base + (ofs)) @@ -318,7 +314,6 @@ static inline u16 __ipw_read16(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) /* alias to 16-bit direct read (low 4K of SRAM/regs), with debug wrapper */ #define ipw_read16(ipw, ofs) __ipw_read16(__FILE__, __LINE__, ipw, ofs) - /* 32-bit direct read (low 4K) */ #define _ipw_read32(ipw, ofs) readl((ipw)->hw_base + (ofs)) @@ -332,7 +327,6 @@ static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs) /* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */ #define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs) - /* multi-byte read (above 4K), with debug wrapper */ static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int); static inline void __ipw_read_indirect(const char *f, int l, @@ -364,7 +358,7 @@ static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value) /* 8-bit indirect write (above 4K) */ static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value) { - u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ + u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ u32 dif_len = reg - aligned_addr; IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); @@ -375,7 +369,7 @@ static void _ipw_write_reg8(struct ipw_priv *priv, u32 reg, u8 value) /* 16-bit indirect write (above 4K) */ static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value) { - u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ + u32 aligned_addr = reg & IPW_INDIRECT_ADDR_MASK; /* dword align */ u32 dif_len = (reg - aligned_addr) & (~0x1ul); IPW_DEBUG_IO(" reg = 0x%8X : value = 0x%8X\n", reg, value); @@ -383,7 +377,6 @@ static void _ipw_write_reg16(struct ipw_priv *priv, u32 reg, u16 value) _ipw_write16(priv, IPW_INDIRECT_DATA + dif_len, value); } - /* 8-bit indirect read (above 4K) */ static u8 _ipw_read_reg8(struct ipw_priv *priv, u32 reg) { @@ -412,7 +405,7 @@ static u32 _ipw_read_reg32(struct ipw_priv *priv, u32 reg) static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, int num) { - u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */ + u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */ u32 dif_len = addr - aligned_addr; u32 i; @@ -449,7 +442,7 @@ static void _ipw_read_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * buf, int num) { - u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */ + u32 aligned_addr = addr & IPW_INDIRECT_ADDR_MASK; /* dword align */ u32 dif_len = addr - aligned_addr; u32 i; @@ -1964,7 +1957,6 @@ static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) #endif printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len); - rc = ipw_queue_tx_hcmd(priv, cmd->cmd, cmd->param, cmd->len, 0); if (rc) { priv->status &= ~STATUS_HCMD_ACTIVE; @@ -2000,7 +1992,7 @@ static int __ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) goto exit; } -exit: + exit: if (priv->cmdlog) { priv->cmdlog[priv->cmdlog_pos++].retcode = rc; priv->cmdlog_pos %= priv->cmdlog_len; @@ -2048,7 +2040,7 @@ static int ipw_send_system_config(struct ipw_priv *priv, } return ipw_send_cmd_pdu(priv, IPW_CMD_SYSTEM_CONFIG, sizeof(*config), - config); + config); } static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) @@ -2059,7 +2051,7 @@ static int ipw_send_ssid(struct ipw_priv *priv, u8 * ssid, int len) } return ipw_send_cmd_pdu(priv, IPW_CMD_SSID, min(len, IW_ESSID_MAX_SIZE), - ssid); + ssid); } static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) @@ -2072,8 +2064,7 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) IPW_DEBUG_INFO("%s: Setting MAC to " MAC_FMT "\n", priv->net_dev->name, MAC_ARG(mac)); - return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, - mac); + return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac); } /* @@ -2133,7 +2124,7 @@ static int ipw_send_scan_request_ext(struct ipw_priv *priv, struct ipw_scan_request_ext *request) { return ipw_send_cmd_pdu(priv, IPW_CMD_SCAN_REQUEST_EXT, - sizeof(*request), request); + sizeof(*request), request); } static int ipw_send_scan_abort(struct ipw_priv *priv) @@ -2153,7 +2144,7 @@ static int ipw_set_sensitivity(struct ipw_priv *priv, u16 sens) }; return ipw_send_cmd_pdu(priv, IPW_CMD_SENSITIVITY_CALIB, sizeof(calib), - &calib); + &calib); } static int ipw_send_associate(struct ipw_priv *priv, @@ -2179,7 +2170,7 @@ static int ipw_send_associate(struct ipw_priv *priv, tmp_associate.atim_window = cpu_to_le16(tmp_associate.atim_window); return ipw_send_cmd_pdu(priv, IPW_CMD_ASSOCIATE, sizeof(tmp_associate), - &tmp_associate); + &tmp_associate); } static int ipw_send_supported_rates(struct ipw_priv *priv, @@ -2191,7 +2182,7 @@ static int ipw_send_supported_rates(struct ipw_priv *priv, } return ipw_send_cmd_pdu(priv, IPW_CMD_SUPPORTED_RATES, sizeof(*rates), - rates); + rates); } static int ipw_set_random_seed(struct ipw_priv *priv) @@ -2216,7 +2207,7 @@ static int ipw_send_card_disable(struct ipw_priv *priv, u32 phy_off) } return ipw_send_cmd_pdu(priv, IPW_CMD_CARD_DISABLE, sizeof(phy_off), - &phy_off); + &phy_off); } static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) @@ -2226,8 +2217,7 @@ static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) return -1; } - return ipw_send_cmd_pdu(priv, IPW_CMD_TX_POWER, sizeof(*power), - power); + return ipw_send_cmd_pdu(priv, IPW_CMD_TX_POWER, sizeof(*power), power); } static int ipw_set_tx_power(struct ipw_priv *priv) @@ -2328,7 +2318,7 @@ static int ipw_send_power_mode(struct ipw_priv *priv, u32 mode) } return ipw_send_cmd_pdu(priv, IPW_CMD_POWER_MODE, sizeof(param), - ¶m); + ¶m); } static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit) @@ -2344,7 +2334,7 @@ static int ipw_send_retry_limit(struct ipw_priv *priv, u8 slimit, u8 llimit) } return ipw_send_cmd_pdu(priv, IPW_CMD_RETRY_LIMIT, sizeof(retry_limit), - &retry_limit); + &retry_limit); } /* @@ -3326,7 +3316,7 @@ static int ipw_load(struct ipw_priv *priv) #ifdef CONFIG_PM } #endif - + /* DMA the ucode into the device */ rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header), ucode->size - sizeof(struct fw_header)); @@ -3356,7 +3346,6 @@ static int ipw_load(struct ipw_priv *priv) IPW_ERROR("Unable to load firmware: %d\n", rc); goto error; } - #ifdef CONFIG_PM fw_loaded = 1; #endif @@ -5291,7 +5280,8 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, "because of age: %ums.\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), - jiffies_to_msecs(jiffies - network->last_scanned)); + jiffies_to_msecs(jiffies - + network->last_scanned)); return 0; } @@ -5502,7 +5492,8 @@ static int ipw_best_network(struct ipw_priv *priv, "assoc attempt).\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), - jiffies_to_msecs(jiffies - network->last_associate)); + jiffies_to_msecs(jiffies - + network->last_associate)); return 0; } @@ -5513,7 +5504,8 @@ static int ipw_best_network(struct ipw_priv *priv, "because of age: %ums.\n", escape_essid(network->ssid, network->ssid_len), MAC_ARG(network->bssid), - jiffies_to_msecs(jiffies - network->last_scanned)); + jiffies_to_msecs(jiffies - + network->last_scanned)); return 0; } @@ -6243,7 +6235,7 @@ static int ipw_set_rsn_capa(struct ipw_priv *priv, IPW_DEBUG_HC("HOST_CMD_RSN_CAPABILITIES\n"); return ipw_send_cmd_pdu(priv, IPW_CMD_RSN_CAPABILITIES, length, - capabilities); + capabilities); } /* @@ -10309,14 +10301,14 @@ static int ipw_config(struct ipw_priv *priv) /* Support Bluetooth if we have BT h/w on board, and user wants to. * Does not support BT priority yet (don't abort or defer our Tx) */ if (bt_coexist) { - unsigned char bt_caps = priv->eeprom[EEPROM_SKU_CAPABILITY]; + unsigned char bt_caps = priv->eeprom[EEPROM_SKU_CAPABILITY]; if (bt_caps & EEPROM_SKU_CAP_BT_CHANNEL_SIG) priv->sys_config.bt_coexistence - |= CFG_BT_COEXISTENCE_SIGNAL_CHNL; + |= CFG_BT_COEXISTENCE_SIGNAL_CHNL; if (bt_caps & EEPROM_SKU_CAP_BT_OOB) priv->sys_config.bt_coexistence - |= CFG_BT_COEXISTENCE_OOB; + |= CFG_BT_COEXISTENCE_OOB; } if (priv->ieee->iw_mode == IW_MODE_ADHOC) diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index c09888b1f1f..eedd347b892 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1453,12 +1453,11 @@ do { if (ipw_debug_level & (level)) \ #define IPW_DOMAIN_0_END 0x1000 #define CLX_MEM_BAR_SIZE 0x1000 - /* Dino/baseband control registers bits */ -#define DINO_ENABLE_SYSTEM 0x80 /* 1 = baseband processor on, 0 = reset */ -#define DINO_ENABLE_CS 0x40 /* 1 = enable ucode load */ -#define DINO_RXFIFO_DATA 0x01 /* 1 = data available */ +#define DINO_ENABLE_SYSTEM 0x80 /* 1 = baseband processor on, 0 = reset */ +#define DINO_ENABLE_CS 0x40 /* 1 = enable ucode load */ +#define DINO_RXFIFO_DATA 0x01 /* 1 = data available */ #define IPW_BASEBAND_CONTROL_STATUS 0X00200000 #define IPW_BASEBAND_TX_FIFO_WRITE 0X00200004 #define IPW_BASEBAND_RX_FIFO_READ 0X00200004 @@ -1575,9 +1574,9 @@ do { if (ipw_debug_level & (level)) \ #define EEPROM_NIC_TYPE_4 4 /* Bluetooth Coexistence capabilities as found in EEPROM_SKU_CAPABILITY */ -#define EEPROM_SKU_CAP_BT_CHANNEL_SIG 0x01 /* we can tell BT our channel # */ -#define EEPROM_SKU_CAP_BT_PRIORITY 0x02 /* BT can take priority over us */ -#define EEPROM_SKU_CAP_BT_OOB 0x04 /* we can signal BT out-of-band */ +#define EEPROM_SKU_CAP_BT_CHANNEL_SIG 0x01 /* we can tell BT our channel # */ +#define EEPROM_SKU_CAP_BT_PRIORITY 0x02 /* BT can take priority over us */ +#define EEPROM_SKU_CAP_BT_OOB 0x04 /* we can signal BT out-of-band */ #define FW_MEM_REG_LOWER_BOUND 0x00300000 #define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40) @@ -1877,11 +1876,11 @@ struct ipw_cmd_log { /* SysConfig command parameters ... */ /* bt_coexistence param */ -#define CFG_BT_COEXISTENCE_SIGNAL_CHNL 0x01 /* tell BT our chnl # */ -#define CFG_BT_COEXISTENCE_DEFER 0x02 /* defer our Tx if BT traffic */ -#define CFG_BT_COEXISTENCE_KILL 0x04 /* kill our Tx if BT traffic */ -#define CFG_BT_COEXISTENCE_WME_OVER_BT 0x08 /* multimedia extensions */ -#define CFG_BT_COEXISTENCE_OOB 0x10 /* signal BT via out-of-band */ +#define CFG_BT_COEXISTENCE_SIGNAL_CHNL 0x01 /* tell BT our chnl # */ +#define CFG_BT_COEXISTENCE_DEFER 0x02 /* defer our Tx if BT traffic */ +#define CFG_BT_COEXISTENCE_KILL 0x04 /* kill our Tx if BT traffic */ +#define CFG_BT_COEXISTENCE_WME_OVER_BT 0x08 /* multimedia extensions */ +#define CFG_BT_COEXISTENCE_OOB 0x10 /* signal BT via out-of-band */ /* clear-to-send to self param */ #define CFG_CTS_TO_ITSELF_ENABLED_MIN 0x00 @@ -1889,9 +1888,9 @@ struct ipw_cmd_log { #define CFG_CTS_TO_ITSELF_ENABLED_DEF CFG_CTS_TO_ITSELF_ENABLED_MIN /* Antenna diversity param (h/w can select best antenna, based on signal) */ -#define CFG_SYS_ANTENNA_BOTH 0x00 /* NIC selects best antenna */ -#define CFG_SYS_ANTENNA_A 0x01 /* force antenna A */ -#define CFG_SYS_ANTENNA_B 0x03 /* force antenna B */ +#define CFG_SYS_ANTENNA_BOTH 0x00 /* NIC selects best antenna */ +#define CFG_SYS_ANTENNA_A 0x01 /* force antenna A */ +#define CFG_SYS_ANTENNA_B 0x03 /* force antenna B */ /* * The definitions below were lifted off the ipw2100 driver, which only -- cgit v1.2.3 From 4644151b7208bec9522cad928a7105e0fc04a2b2 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:37:59 +0800 Subject: [PATCH] ipw2200: Semaphore to mutexes conversion The conversion was generated via scripts, and the result was validated automatically via a script as well. Signed-off-by: Ingo Molnar Cc: Ronald Bultje Cc: "David S. Miller" Cc: Jeff Garzik Cc: Yi Zhu Cc: James Ketrenos Signed-off-by: Andrew Morton Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 294 ++++++++++++++++++++--------------------- drivers/net/wireless/ipw2200.h | 3 +- 2 files changed, 149 insertions(+), 148 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index f793cd8f8d7..fdb8065a808 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -812,9 +812,9 @@ static void ipw_led_link_on(struct ipw_priv *priv) static void ipw_bg_led_link_on(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_led_link_on(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static void ipw_led_link_off(struct ipw_priv *priv) @@ -856,9 +856,9 @@ static void ipw_led_link_off(struct ipw_priv *priv) static void ipw_bg_led_link_off(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_led_link_off(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static void __ipw_led_activity_on(struct ipw_priv *priv) @@ -935,9 +935,9 @@ static void ipw_led_activity_off(struct ipw_priv *priv) static void ipw_bg_led_activity_off(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_led_activity_off(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static void ipw_led_band_on(struct ipw_priv *priv) @@ -2094,9 +2094,9 @@ static void ipw_adapter_restart(void *adapter) static void ipw_bg_adapter_restart(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_adapter_restart(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } #define IPW_SCAN_CHECK_WATCHDOG (5 * HZ) @@ -2115,9 +2115,9 @@ static void ipw_scan_check(void *data) static void ipw_bg_scan_check(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_scan_check(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static int ipw_send_scan_request_ext(struct ipw_priv *priv, @@ -3735,9 +3735,9 @@ static int ipw_disassociate(void *data) static void ipw_bg_disassociate(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_disassociate(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static void ipw_system_config(void *data) @@ -4097,9 +4097,9 @@ static void ipw_gather_stats(struct ipw_priv *priv) static void ipw_bg_gather_stats(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_gather_stats(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } /* Missed beacon behavior: @@ -4931,9 +4931,9 @@ static void ipw_rx_queue_replenish(void *data) static void ipw_bg_rx_queue_replenish(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_rx_queue_replenish(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } /* Assumes that the skb field of the buffers in 'pool' is kept accurate. @@ -5390,7 +5390,7 @@ static void ipw_merge_adhoc_network(void *data) return; } - down(&priv->sem); + mutex_lock(&priv->mutex); if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { IPW_DEBUG_MERGE("remove network %s\n", escape_essid(priv->essid, @@ -5400,7 +5400,7 @@ static void ipw_merge_adhoc_network(void *data) ipw_disassociate(priv); priv->assoc_network = match.network; - up(&priv->sem); + mutex_unlock(&priv->mutex); return; } } @@ -5835,9 +5835,9 @@ static void ipw_adhoc_check(void *data) static void ipw_bg_adhoc_check(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_adhoc_check(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } #ifdef CONFIG_IPW2200_DEBUG @@ -6064,7 +6064,7 @@ static int ipw_request_scan(struct ipw_priv *priv) (priv->status & STATUS_EXIT_PENDING)) return 0; - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->status & STATUS_SCANNING) { IPW_DEBUG_HC("Concurrent scan requested. Ignoring.\n"); @@ -6172,16 +6172,16 @@ static int ipw_request_scan(struct ipw_priv *priv) queue_delayed_work(priv->workqueue, &priv->scan_check, IPW_SCAN_CHECK_WATCHDOG); done: - up(&priv->sem); + mutex_unlock(&priv->mutex); return err; } static void ipw_bg_abort_scan(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_abort_scan(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static int ipw_wpa_enable(struct ipw_priv *priv, int value) @@ -6256,7 +6256,7 @@ static int ipw_wx_set_genie(struct net_device *dev, (wrqu->data.length && extra == NULL)) return -EINVAL; - //down(&priv->sem); + //mutex_lock(&priv->mutex); //if (!ieee->wpa_enabled) { // err = -EOPNOTSUPP; @@ -6282,7 +6282,7 @@ static int ipw_wx_set_genie(struct net_device *dev, ipw_wpa_assoc_frame(priv, ieee->wpa_ie, ieee->wpa_ie_len); out: - //up(&priv->sem); + //mutex_unlock(&priv->mutex); return err; } @@ -6295,7 +6295,7 @@ static int ipw_wx_get_genie(struct net_device *dev, struct ieee80211_device *ieee = priv->ieee; int err = 0; - //down(&priv->sem); + //mutex_lock(&priv->mutex); //if (!ieee->wpa_enabled) { // err = -EOPNOTSUPP; @@ -6316,7 +6316,7 @@ static int ipw_wx_get_genie(struct net_device *dev, memcpy(extra, ieee->wpa_ie, ieee->wpa_ie_len); out: - //up(&priv->sem); + //mutex_unlock(&priv->mutex); return err; } @@ -6976,12 +6976,12 @@ static void ipw_bg_qos_activate(void *data) if (priv == NULL) return; - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->status & STATUS_ASSOCIATED) ipw_qos_activate(priv, &(priv->assoc_network->qos_data)); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static int ipw_handle_probe_response(struct net_device *dev, @@ -7283,9 +7283,9 @@ static void ipw_roam(void *data) static void ipw_bg_roam(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_roam(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static int ipw_associate(void *data) @@ -7380,9 +7380,9 @@ static int ipw_associate(void *data) static void ipw_bg_associate(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_associate(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, @@ -8131,7 +8131,7 @@ static int ipw_wx_get_name(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->status & STATUS_RF_KILL_MASK) strcpy(wrqu->name, "radio off"); else if (!(priv->status & STATUS_ASSOCIATED)) @@ -8140,7 +8140,7 @@ static int ipw_wx_get_name(struct net_device *dev, snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", ipw_modes[priv->assoc_request.ieee_mode]); IPW_DEBUG_WX("Name: %s\n", wrqu->name); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8209,9 +8209,9 @@ static int ipw_wx_set_freq(struct net_device *dev, if (fwrq->m == 0) { IPW_DEBUG_WX("SET Freq/Channel -> any\n"); - down(&priv->sem); + mutex_lock(&priv->mutex); ret = ipw_set_channel(priv, 0); - up(&priv->sem); + mutex_unlock(&priv->mutex); return ret; } /* if setting by freq convert to channel */ @@ -8239,9 +8239,9 @@ static int ipw_wx_set_freq(struct net_device *dev, } IPW_DEBUG_WX("SET Freq/Channel -> %d \n", fwrq->m); - down(&priv->sem); + mutex_lock(&priv->mutex); ret = ipw_set_channel(priv, channel); - up(&priv->sem); + mutex_unlock(&priv->mutex); return ret; } @@ -8255,14 +8255,14 @@ static int ipw_wx_get_freq(struct net_device *dev, /* If we are associated, trying to associate, or have a statically * configured CHANNEL then return that; otherwise return ANY */ - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->config & CFG_STATIC_CHANNEL || priv->status & (STATUS_ASSOCIATING | STATUS_ASSOCIATED)) wrqu->freq.m = priv->channel; else wrqu->freq.m = 0; - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET Freq/Channel -> %d \n", priv->channel); return 0; } @@ -8292,7 +8292,7 @@ static int ipw_wx_set_mode(struct net_device *dev, if (wrqu->mode == priv->ieee->iw_mode) return 0; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_sw_reset(priv, 0); @@ -8315,7 +8315,7 @@ static int ipw_wx_set_mode(struct net_device *dev, priv->ieee->iw_mode = wrqu->mode; queue_work(priv->workqueue, &priv->adapter_restart); - up(&priv->sem); + mutex_unlock(&priv->mutex); return err; } @@ -8324,10 +8324,10 @@ static int ipw_wx_get_mode(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->mode = priv->ieee->iw_mode; IPW_DEBUG_WX("Get MODE -> %d\n", wrqu->mode); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8374,7 +8374,7 @@ static int ipw_wx_get_range(struct net_device *dev, range->avg_qual.level = 0; /* FIXME to real average level */ range->avg_qual.noise = 0; range->avg_qual.updated = 7; /* Updated all three */ - down(&priv->sem); + mutex_lock(&priv->mutex); range->num_bitrates = min(priv->rates.num_rates, (u8) IW_MAX_BITRATES); for (i = 0; i < range->num_bitrates; i++) @@ -8416,7 +8416,7 @@ static int ipw_wx_get_range(struct net_device *dev, range->num_channels = i; range->num_frequency = i; - up(&priv->sem); + mutex_unlock(&priv->mutex); /* Event capability (kernel + driver) */ range->event_capa[0] = (IW_EVENT_CAPA_K_0 | @@ -8443,7 +8443,7 @@ static int ipw_wx_set_wap(struct net_device *dev, if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) return -EINVAL; - down(&priv->sem); + mutex_lock(&priv->mutex); if (!memcmp(any, wrqu->ap_addr.sa_data, ETH_ALEN) || !memcmp(off, wrqu->ap_addr.sa_data, ETH_ALEN)) { /* we disable mandatory BSSID association */ @@ -8452,14 +8452,14 @@ static int ipw_wx_set_wap(struct net_device *dev, IPW_DEBUG_ASSOC("Attempting to associate with new " "parameters.\n"); ipw_associate(priv); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } priv->config |= CFG_STATIC_BSSID; if (!memcmp(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN)) { IPW_DEBUG_WX("BSSID set to current BSSID.\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8473,7 +8473,7 @@ static int ipw_wx_set_wap(struct net_device *dev, if (!ipw_disassociate(priv)) ipw_associate(priv); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8484,7 +8484,7 @@ static int ipw_wx_get_wap(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->config & CFG_STATIC_BSSID || priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { wrqu->ap_addr.sa_family = ARPHRD_ETHER; @@ -8494,7 +8494,7 @@ static int ipw_wx_get_wap(struct net_device *dev, IPW_DEBUG_WX("Getting WAP BSSID: " MAC_FMT "\n", MAC_ARG(wrqu->ap_addr.sa_data)); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8505,7 +8505,7 @@ static int ipw_wx_set_essid(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); char *essid = ""; /* ANY */ int length = 0; - down(&priv->sem); + mutex_lock(&priv->mutex); if (wrqu->essid.flags && wrqu->essid.length) { length = wrqu->essid.length - 1; essid = extra; @@ -8520,7 +8520,7 @@ static int ipw_wx_set_essid(struct net_device *dev, priv->config &= ~CFG_STATIC_ESSID; ipw_associate(priv); } - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8530,7 +8530,7 @@ static int ipw_wx_set_essid(struct net_device *dev, if (priv->essid_len == length && !memcmp(priv->essid, extra, length)) { IPW_DEBUG_WX("ESSID set to current ESSID.\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8545,7 +8545,7 @@ static int ipw_wx_set_essid(struct net_device *dev, if (!ipw_disassociate(priv)) ipw_associate(priv); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8557,7 +8557,7 @@ static int ipw_wx_get_essid(struct net_device *dev, /* If we are associated, trying to associate, or have a statically * configured ESSID then return that; otherwise return ANY */ - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->config & CFG_STATIC_ESSID || priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { IPW_DEBUG_WX("Getting essid: '%s'\n", @@ -8570,7 +8570,7 @@ static int ipw_wx_get_essid(struct net_device *dev, wrqu->essid.length = 0; wrqu->essid.flags = 0; /* active */ } - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8583,12 +8583,12 @@ static int ipw_wx_set_nick(struct net_device *dev, IPW_DEBUG_WX("Setting nick to '%s'\n", extra); if (wrqu->data.length > IW_ESSID_MAX_SIZE) return -E2BIG; - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->data.length = min((size_t) wrqu->data.length, sizeof(priv->nick)); memset(priv->nick, 0, sizeof(priv->nick)); memcpy(priv->nick, extra, wrqu->data.length); IPW_DEBUG_TRACE("<<\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8599,11 +8599,11 @@ static int ipw_wx_get_nick(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); IPW_DEBUG_WX("Getting nick\n"); - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->data.length = strlen(priv->nick) + 1; memcpy(extra, priv->nick, wrqu->data.length); wrqu->data.flags = 1; /* active */ - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8696,7 +8696,7 @@ static int ipw_wx_set_rate(struct net_device *dev, apply: IPW_DEBUG_WX("Setting rate mask to 0x%08X [%s]\n", mask, fixed ? "fixed" : "sub-rates"); - down(&priv->sem); + mutex_lock(&priv->mutex); if (mask == IEEE80211_DEFAULT_RATES_MASK) { priv->config &= ~CFG_FIXED_RATE; ipw_set_fixed_rate(priv, priv->ieee->mode); @@ -8705,7 +8705,7 @@ static int ipw_wx_set_rate(struct net_device *dev, if (priv->rates_mask == mask) { IPW_DEBUG_WX("Mask set to current mask.\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8716,7 +8716,7 @@ static int ipw_wx_set_rate(struct net_device *dev, if (!ipw_disassociate(priv)) ipw_associate(priv); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -8725,9 +8725,9 @@ static int ipw_wx_get_rate(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->bitrate.value = priv->last_rate; - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value); return 0; } @@ -8737,20 +8737,20 @@ static int ipw_wx_set_rts(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); if (wrqu->rts.disabled) priv->rts_threshold = DEFAULT_RTS_THRESHOLD; else { if (wrqu->rts.value < MIN_RTS_THRESHOLD || wrqu->rts.value > MAX_RTS_THRESHOLD) { - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EINVAL; } priv->rts_threshold = wrqu->rts.value; } ipw_send_rts_threshold(priv, priv->rts_threshold); - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("SET RTS Threshold -> %d \n", priv->rts_threshold); return 0; } @@ -8760,11 +8760,11 @@ static int ipw_wx_get_rts(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->rts.value = priv->rts_threshold; wrqu->rts.fixed = 0; /* no auto select */ wrqu->rts.disabled = (wrqu->rts.value == DEFAULT_RTS_THRESHOLD); - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET RTS Threshold -> %d \n", wrqu->rts.value); return 0; } @@ -8776,7 +8776,7 @@ static int ipw_wx_set_txpow(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); int err = 0; - down(&priv->sem); + mutex_lock(&priv->mutex); if (ipw_radio_kill_sw(priv, wrqu->power.disabled)) { err = -EINPROGRESS; goto out; @@ -8799,7 +8799,7 @@ static int ipw_wx_set_txpow(struct net_device *dev, priv->tx_power = wrqu->power.value; err = ipw_set_tx_power(priv); out: - up(&priv->sem); + mutex_unlock(&priv->mutex); return err; } @@ -8808,12 +8808,12 @@ static int ipw_wx_get_txpow(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->power.value = priv->tx_power; wrqu->power.fixed = 1; wrqu->power.flags = IW_TXPOW_DBM; wrqu->power.disabled = (priv->status & STATUS_RF_KILL_MASK) ? 1 : 0; - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET TX Power -> %s %d \n", wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value); @@ -8826,13 +8826,13 @@ static int ipw_wx_set_frag(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); if (wrqu->frag.disabled) priv->ieee->fts = DEFAULT_FTS; else { if (wrqu->frag.value < MIN_FRAG_THRESHOLD || wrqu->frag.value > MAX_FRAG_THRESHOLD) { - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EINVAL; } @@ -8840,7 +8840,7 @@ static int ipw_wx_set_frag(struct net_device *dev, } ipw_send_frag_threshold(priv, wrqu->frag.value); - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("SET Frag Threshold -> %d \n", wrqu->frag.value); return 0; } @@ -8850,11 +8850,11 @@ static int ipw_wx_get_frag(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->frag.value = priv->ieee->fts; wrqu->frag.fixed = 0; /* no auto select */ wrqu->frag.disabled = (wrqu->frag.value == DEFAULT_FTS); - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET Frag Threshold -> %d \n", wrqu->frag.value); return 0; @@ -8875,7 +8875,7 @@ static int ipw_wx_set_retry(struct net_device *dev, if (wrqu->retry.value < 0 || wrqu->retry.value > 255) return -EINVAL; - down(&priv->sem); + mutex_lock(&priv->mutex); if (wrqu->retry.flags & IW_RETRY_MIN) priv->short_retry_limit = (u8) wrqu->retry.value; else if (wrqu->retry.flags & IW_RETRY_MAX) @@ -8887,7 +8887,7 @@ static int ipw_wx_set_retry(struct net_device *dev, ipw_send_retry_limit(priv, priv->short_retry_limit, priv->long_retry_limit); - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("SET retry limit -> short:%d long:%d\n", priv->short_retry_limit, priv->long_retry_limit); return 0; @@ -8899,11 +8899,11 @@ static int ipw_wx_get_retry(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); wrqu->retry.disabled = 0; if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) { - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EINVAL; } @@ -8917,7 +8917,7 @@ static int ipw_wx_get_retry(struct net_device *dev, wrqu->retry.flags = IW_RETRY_LIMIT; wrqu->retry.value = priv->short_retry_limit; } - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET retry -> %d \n", wrqu->retry.value); @@ -8934,7 +8934,7 @@ static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid, (priv->status & STATUS_EXIT_PENDING)) return 0; - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->status & STATUS_RF_KILL_MASK) { IPW_DEBUG_HC("Aborting scan due to RF kill activation\n"); @@ -8986,7 +8986,7 @@ static int ipw_request_direct_scan(struct ipw_priv *priv, char *essid, priv->status |= STATUS_SCANNING; done: - up(&priv->sem); + mutex_unlock(&priv->mutex); return err; } @@ -9029,7 +9029,7 @@ static int ipw_wx_set_encode(struct net_device *dev, int ret; u32 cap = priv->capability; - down(&priv->sem); + mutex_lock(&priv->mutex); ret = ieee80211_wx_set_encode(priv->ieee, info, wrqu, key); /* In IBSS mode, we need to notify the firmware to update @@ -9039,7 +9039,7 @@ static int ipw_wx_set_encode(struct net_device *dev, priv->status & STATUS_ASSOCIATED) ipw_disassociate(priv); - up(&priv->sem); + mutex_unlock(&priv->mutex); return ret; } @@ -9057,17 +9057,17 @@ static int ipw_wx_set_power(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); int err; - down(&priv->sem); + mutex_lock(&priv->mutex); if (wrqu->power.disabled) { priv->power_mode = IPW_POWER_LEVEL(priv->power_mode); err = ipw_send_power_mode(priv, IPW_POWER_MODE_CAM); if (err) { IPW_DEBUG_WX("failed setting power mode.\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return err; } IPW_DEBUG_WX("SET Power Management Mode -> off\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9079,7 +9079,7 @@ static int ipw_wx_set_power(struct net_device *dev, default: /* Otherwise we don't support it */ IPW_DEBUG_WX("SET PM Mode: %X not supported.\n", wrqu->power.flags); - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EOPNOTSUPP; } @@ -9092,12 +9092,12 @@ static int ipw_wx_set_power(struct net_device *dev, err = ipw_send_power_mode(priv, IPW_POWER_LEVEL(priv->power_mode)); if (err) { IPW_DEBUG_WX("failed setting power mode.\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return err; } IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9106,13 +9106,13 @@ static int ipw_wx_get_power(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); if (!(priv->power_mode & IPW_POWER_ENABLED)) wrqu->power.disabled = 1; else wrqu->power.disabled = 0; - up(&priv->sem); + mutex_unlock(&priv->mutex); IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); return 0; @@ -9125,7 +9125,7 @@ static int ipw_wx_set_powermode(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); int mode = *(int *)extra; int err; - down(&priv->sem); + mutex_lock(&priv->mutex); if ((mode < 1) || (mode > IPW_POWER_LIMIT)) { mode = IPW_POWER_AC; priv->power_mode = mode; @@ -9138,11 +9138,11 @@ static int ipw_wx_set_powermode(struct net_device *dev, if (err) { IPW_DEBUG_WX("failed setting power mode.\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return err; } } - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9191,7 +9191,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, IPW_WARNING("Attempt to set invalid wireless mode: %d\n", mode); return -EINVAL; } - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->adapter == IPW_2915ABG) { priv->ieee->abg_true = 1; if (mode & IEEE_A) { @@ -9203,7 +9203,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, if (mode & IEEE_A) { IPW_WARNING("Attempt to set 2200BG into " "802.11a mode\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EINVAL; } @@ -9240,7 +9240,7 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n", mode & IEEE_A ? 'a' : '.', mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.'); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9249,7 +9249,7 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); switch (priv->ieee->mode) { case IEEE_A: strncpy(extra, "802.11a (1)", MAX_WX_STRING); @@ -9280,7 +9280,7 @@ static int ipw_wx_get_wireless_mode(struct net_device *dev, IPW_DEBUG_WX("PRIV GET MODE: %s\n", extra); wrqu->data.length = strlen(extra) + 1; - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9291,7 +9291,7 @@ static int ipw_wx_set_preamble(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); int mode = *(int *)extra; - down(&priv->sem); + mutex_lock(&priv->mutex); /* Switching from SHORT -> LONG requires a disassociation */ if (mode == 1) { if (!(priv->config & CFG_PREAMBLE_LONG)) { @@ -9310,11 +9310,11 @@ static int ipw_wx_set_preamble(struct net_device *dev, priv->config &= ~CFG_PREAMBLE_LONG; goto done; } - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EINVAL; done: - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9323,12 +9323,12 @@ static int ipw_wx_get_preamble(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); if (priv->config & CFG_PREAMBLE_LONG) snprintf(wrqu->name, IFNAMSIZ, "long (1)"); else snprintf(wrqu->name, IFNAMSIZ, "auto (0)"); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9340,7 +9340,7 @@ static int ipw_wx_set_monitor(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); int *parms = (int *)extra; int enable = (parms[0] > 0); - down(&priv->sem); + mutex_lock(&priv->mutex); IPW_DEBUG_WX("SET MONITOR: %d %d\n", enable, parms[1]); if (enable) { if (priv->ieee->iw_mode != IW_MODE_MONITOR) { @@ -9355,13 +9355,13 @@ static int ipw_wx_set_monitor(struct net_device *dev, ipw_set_channel(priv, parms[1]); } else { if (priv->ieee->iw_mode != IW_MODE_MONITOR) { - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } priv->net_dev->type = ARPHRD_ETHER; queue_work(priv->workqueue, &priv->adapter_restart); } - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9391,7 +9391,7 @@ static int ipw_wx_sw_reset(struct net_device *dev, IPW_DEBUG_WX("SW_RESET\n"); - down(&priv->sem); + mutex_lock(&priv->mutex); ret = ipw_sw_reset(priv, 0); if (!ret) { @@ -9403,9 +9403,9 @@ static int ipw_wx_sw_reset(struct net_device *dev, * module parameter, so take appropriate action */ ipw_radio_kill_sw(priv, priv->status & STATUS_RF_KILL_SW); - up(&priv->sem); + mutex_unlock(&priv->mutex); ieee80211_wx_set_encode(priv->ieee, info, &wrqu_sec, NULL); - down(&priv->sem); + mutex_lock(&priv->mutex); if (!(priv->status & STATUS_RF_KILL_MASK)) { /* Configuration likely changed -- force [re]association */ @@ -9415,7 +9415,7 @@ static int ipw_wx_sw_reset(struct net_device *dev, ipw_associate(priv); } - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9612,11 +9612,11 @@ static int ipw_net_open(struct net_device *dev) struct ipw_priv *priv = ieee80211_priv(dev); IPW_DEBUG_INFO("dev->open\n"); /* we should be verifying the device is ready to be opened */ - down(&priv->sem); + mutex_lock(&priv->mutex); if (!(priv->status & STATUS_RF_KILL_MASK) && (priv->status & STATUS_ASSOCIATED)) netif_start_queue(dev); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9895,13 +9895,13 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p) struct sockaddr *addr = p; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - down(&priv->sem); + mutex_lock(&priv->mutex); priv->config |= CFG_CUSTOM_MAC; memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n", priv->net_dev->name, MAC_ARG(priv->mac_addr)); queue_work(priv->workqueue, &priv->adapter_restart); - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -9945,9 +9945,9 @@ static int ipw_ethtool_get_eeprom(struct net_device *dev, if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) return -EINVAL; - down(&p->sem); + mutex_lock(&p->mutex); memcpy(bytes, &p->eeprom[eeprom->offset], eeprom->len); - up(&p->sem); + mutex_unlock(&p->mutex); return 0; } @@ -9959,12 +9959,12 @@ static int ipw_ethtool_set_eeprom(struct net_device *dev, if (eeprom->offset + eeprom->len > IPW_EEPROM_IMAGE_SIZE) return -EINVAL; - down(&p->sem); + mutex_lock(&p->mutex); memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len); for (i = IPW_EEPROM_DATA; i < IPW_EEPROM_DATA + IPW_EEPROM_IMAGE_SIZE; i++) ipw_write8(p, i, p->eeprom[i]); - up(&p->sem); + mutex_unlock(&p->mutex); return 0; } @@ -10059,9 +10059,9 @@ static void ipw_rf_kill(void *adapter) static void ipw_bg_rf_kill(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_rf_kill(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static void ipw_link_up(struct ipw_priv *priv) @@ -10094,9 +10094,9 @@ static void ipw_link_up(struct ipw_priv *priv) static void ipw_bg_link_up(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_link_up(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static void ipw_link_down(struct ipw_priv *priv) @@ -10122,9 +10122,9 @@ static void ipw_link_down(struct ipw_priv *priv) static void ipw_bg_link_down(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_link_down(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static int ipw_setup_deferred_work(struct ipw_priv *priv) @@ -10801,9 +10801,9 @@ static int ipw_up(struct ipw_priv *priv) static void ipw_bg_up(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_up(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } static void ipw_deinit(struct ipw_priv *priv) @@ -10872,23 +10872,23 @@ static void ipw_down(struct ipw_priv *priv) static void ipw_bg_down(void *data) { struct ipw_priv *priv = data; - down(&priv->sem); + mutex_lock(&priv->mutex); ipw_down(data); - up(&priv->sem); + mutex_unlock(&priv->mutex); } /* Called by register_netdev() */ static int ipw_net_init(struct net_device *dev) { struct ipw_priv *priv = ieee80211_priv(dev); - down(&priv->sem); + mutex_lock(&priv->mutex); if (ipw_up(priv)) { - up(&priv->sem); + mutex_unlock(&priv->mutex); return -EIO; } - up(&priv->sem); + mutex_unlock(&priv->mutex); return 0; } @@ -10978,7 +10978,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) for (i = 0; i < IPW_IBSS_MAC_HASH_SIZE; i++) INIT_LIST_HEAD(&priv->ibss_mac_hash[i]); - init_MUTEX(&priv->sem); + mutex_init(&priv->mutex); if (pci_enable_device(pdev)) { err = -ENODEV; goto out_free_ieee80211; @@ -11036,7 +11036,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SET_MODULE_OWNER(net_dev); SET_NETDEV_DEV(net_dev, &pdev->dev); - down(&priv->sem); + mutex_lock(&priv->mutex); priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; priv->ieee->set_security = shim__set_security; @@ -11069,11 +11069,11 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = sysfs_create_group(&pdev->dev.kobj, &ipw_attribute_group); if (err) { IPW_ERROR("failed to create sysfs device attributes\n"); - up(&priv->sem); + mutex_unlock(&priv->mutex); goto out_release_irq; } - up(&priv->sem); + mutex_unlock(&priv->mutex); err = register_netdev(net_dev); if (err) { IPW_ERROR("failed to register network device\n"); @@ -11110,13 +11110,13 @@ static void ipw_pci_remove(struct pci_dev *pdev) if (!priv) return; - down(&priv->sem); + mutex_lock(&priv->mutex); priv->status |= STATUS_EXIT_PENDING; ipw_down(priv); sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); - up(&priv->sem); + mutex_unlock(&priv->mutex); unregister_netdev(priv->net_dev); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index eedd347b892..5405ba105ab 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -1121,7 +1122,7 @@ struct ipw_priv { struct ieee80211_device *ieee; spinlock_t lock; - struct semaphore sem; + struct mutex mutex; /* basic pci-network driver stuff */ struct pci_dev *pci_dev; -- cgit v1.2.3 From bde37d037715bef4a67d58d00fecbe4c71836cab Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 24 Jan 2006 16:38:08 +0800 Subject: [PATCH] ipw2200: Disable hwcrypto by default After looking at the mailing list (and experiencing permanent driver lockups while using hwcrypto=1) I think that disabling this option by default would be better than otherwise. Signed-off-by: Andreas Happe Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index fdb8065a808..18e00fe8a21 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -56,7 +56,7 @@ static int auto_create = 1; static int led = 0; static int disable = 0; static int bt_coexist = 0; -static int hwcrypto = 1; +static int hwcrypto = 0; static int roaming = 1; static const char ipw_modes[] = { 'a', 'b', 'g', '?' @@ -11304,7 +11304,7 @@ module_param(bt_coexist, int, 0444); MODULE_PARM_DESC(bt_coexist, "enable bluetooth coexistence (default off)"); module_param(hwcrypto, int, 0444); -MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default on)"); +MODULE_PARM_DESC(hwcrypto, "enable hardware crypto (default off)"); module_param(cmdlog, int, 0444); MODULE_PARM_DESC(cmdlog, -- cgit v1.2.3 From 4be757dd4c00ddabff2d6faf639466bb5d76bc79 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 30 Jan 2006 11:58:00 -0500 Subject: [PATCH] wireless/airo: add IWENCODEEXT and IWAUTH support This patch adds IWENCODEEXT and IWAUTH support to the airo driver for WEP and unencrypted operation. No WPA though. It allows the driver to operate more willingly with wpa_supplicant and NetworkManager. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 276 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 274 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 9c577f7b6e5..ef6495b0789 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -5756,11 +5756,13 @@ static int airo_set_wap(struct net_device *dev, Cmd cmd; Resp rsp; APListRid APList_rid; - static const unsigned char bcast[ETH_ALEN] = { 255, 255, 255, 255, 255, 255 }; + static const u8 any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + static const u8 off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; if (awrq->sa_family != ARPHRD_ETHER) return -EINVAL; - else if (!memcmp(bcast, awrq->sa_data, ETH_ALEN)) { + else if (!memcmp(any, awrq->sa_data, ETH_ALEN) || + !memcmp(off, awrq->sa_data, ETH_ALEN)) { memset(&cmd, 0, sizeof(cmd)); cmd.cmd=CMD_LOSE_SYNC; if (down_interruptible(&local->sem)) @@ -6249,6 +6251,267 @@ static int airo_get_encode(struct net_device *dev, return 0; } +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set extended Encryption parameters + */ +static int airo_set_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct airo_info *local = dev->priv; + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + CapabilityRid cap_rid; /* Card capability info */ + int perm = ( encoding->flags & IW_ENCODE_TEMP ? 0 : 1 ); + u16 currentAuthType = local->config.authType; + int idx, key_len, alg = ext->alg; /* Check encryption mode */ + wep_key_t key; + + /* Is WEP supported ? */ + readCapabilityRid(local, &cap_rid, 1); + /* Older firmware doesn't support this... + if(!(cap_rid.softCap & 2)) { + return -EOPNOTSUPP; + } */ + readConfigRid(local, 1); + + /* Determine and validate the key index */ + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1)) + return -EINVAL; + idx--; + } else + idx = get_wep_key(local, 0xffff); + + if (encoding->flags & IW_ENCODE_DISABLED) + alg = IW_ENCODE_ALG_NONE; + + /* Just setting the transmit key? */ + if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + set_wep_key(local, idx, NULL, 0, perm, 1); + } else { + /* Set the requested key first */ + memset(key.key, 0, MAX_KEY_SIZE); + switch (alg) { + case IW_ENCODE_ALG_NONE: + key.len = 0; + break; + case IW_ENCODE_ALG_WEP: + if (ext->key_len > MIN_KEY_SIZE) { + key.len = MAX_KEY_SIZE; + } else if (ext->key_len > 0) { + key.len = MIN_KEY_SIZE; + } else { + return -EINVAL; + } + key_len = min (ext->key_len, key.len); + memcpy(key.key, ext->key, key_len); + break; + default: + return -EINVAL; + } + /* Send the key to the card */ + set_wep_key(local, idx, key.key, key.len, perm, 1); + } + + /* Read the flags */ + if(encoding->flags & IW_ENCODE_DISABLED) + local->config.authType = AUTH_OPEN; // disable encryption + if(encoding->flags & IW_ENCODE_RESTRICTED) + local->config.authType = AUTH_SHAREDKEY; // Only Both + if(encoding->flags & IW_ENCODE_OPEN) + local->config.authType = AUTH_ENCRYPT; // Only Wep + /* Commit the changes to flags if needed */ + if (local->config.authType != currentAuthType) + set_bit (FLAG_COMMIT, &local->flags); + + return -EINPROGRESS; +} + + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get extended Encryption parameters + */ +static int airo_get_encodeext(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, + char *extra) +{ + struct airo_info *local = dev->priv; + struct iw_point *encoding = &wrqu->encoding; + struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; + CapabilityRid cap_rid; /* Card capability info */ + int idx, max_key_len; + + /* Is it supported ? */ + readCapabilityRid(local, &cap_rid, 1); + if(!(cap_rid.softCap & 2)) { + return -EOPNOTSUPP; + } + readConfigRid(local, 1); + + max_key_len = encoding->length - sizeof(*ext); + if (max_key_len < 0) + return -EINVAL; + + idx = encoding->flags & IW_ENCODE_INDEX; + if (idx) { + if (idx < 1 || idx > ((cap_rid.softCap & 0x80) ? 4:1)) + return -EINVAL; + idx--; + } else + idx = get_wep_key(local, 0xffff); + + encoding->flags = idx + 1; + memset(ext, 0, sizeof(*ext)); + + /* Check encryption mode */ + switch(local->config.authType) { + case AUTH_ENCRYPT: + encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED; + break; + case AUTH_SHAREDKEY: + encoding->flags = IW_ENCODE_ALG_WEP | IW_ENCODE_ENABLED; + break; + default: + case AUTH_OPEN: + encoding->flags = IW_ENCODE_ALG_NONE | IW_ENCODE_DISABLED; + break; + } + /* We can't return the key, so set the proper flag and return zero */ + encoding->flags |= IW_ENCODE_NOKEY; + memset(extra, 0, 16); + + /* Copy the key to the user buffer */ + ext->key_len = get_wep_key(local, idx); + if (ext->key_len > 16) { + ext->key_len=0; + } + + return 0; +} + + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : set extended authentication parameters + */ +static int airo_set_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct airo_info *local = dev->priv; + struct iw_param *param = &wrqu->param; + u16 currentAuthType = local->config.authType; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_WPA_VERSION: + case IW_AUTH_CIPHER_PAIRWISE: + case IW_AUTH_CIPHER_GROUP: + case IW_AUTH_KEY_MGMT: + case IW_AUTH_RX_UNENCRYPTED_EAPOL: + case IW_AUTH_PRIVACY_INVOKED: + /* + * airo does not use these parameters + */ + break; + + case IW_AUTH_DROP_UNENCRYPTED: + if (param->value) { + /* Only change auth type if unencrypted */ + if (currentAuthType == AUTH_OPEN) + local->config.authType = AUTH_ENCRYPT; + } else { + local->config.authType = AUTH_OPEN; + } + + /* Commit the changes to flags if needed */ + if (local->config.authType != currentAuthType) + set_bit (FLAG_COMMIT, &local->flags); + break; + + case IW_AUTH_80211_AUTH_ALG: { + /* FIXME: What about AUTH_OPEN? This API seems to + * disallow setting our auth to AUTH_OPEN. + */ + if (param->value & IW_AUTH_ALG_SHARED_KEY) { + local->config.authType = AUTH_SHAREDKEY; + } else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) { + local->config.authType = AUTH_ENCRYPT; + } else + return -EINVAL; + break; + + /* Commit the changes to flags if needed */ + if (local->config.authType != currentAuthType) + set_bit (FLAG_COMMIT, &local->flags); + } + + case IW_AUTH_WPA_ENABLED: + /* Silently accept disable of WPA */ + if (param->value > 0) + return -EOPNOTSUPP; + break; + + default: + return -EOPNOTSUPP; + } + return -EINPROGRESS; +} + + +/*------------------------------------------------------------------*/ +/* + * Wireless Handler : get extended authentication parameters + */ +static int airo_get_auth(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct airo_info *local = dev->priv; + struct iw_param *param = &wrqu->param; + u16 currentAuthType = local->config.authType; + + switch (param->flags & IW_AUTH_INDEX) { + case IW_AUTH_DROP_UNENCRYPTED: + switch (currentAuthType) { + case AUTH_SHAREDKEY: + case AUTH_ENCRYPT: + param->value = 1; + break; + default: + param->value = 0; + break; + } + break; + + case IW_AUTH_80211_AUTH_ALG: + switch (currentAuthType) { + case AUTH_SHAREDKEY: + param->value = IW_AUTH_ALG_SHARED_KEY; + break; + case AUTH_ENCRYPT: + default: + param->value = IW_AUTH_ALG_OPEN_SYSTEM; + break; + } + break; + + case IW_AUTH_WPA_ENABLED: + param->value = 0; + break; + + default: + return -EOPNOTSUPP; + } + return 0; +} + + /*------------------------------------------------------------------*/ /* * Wireless Handler : set Tx-Power @@ -7005,6 +7268,15 @@ static const iw_handler airo_handler[] = (iw_handler) airo_get_encode, /* SIOCGIWENCODE */ (iw_handler) airo_set_power, /* SIOCSIWPOWER */ (iw_handler) airo_get_power, /* SIOCGIWPOWER */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCSIWGENIE */ + (iw_handler) NULL, /* SIOCGIWGENIE */ + (iw_handler) airo_set_auth, /* SIOCSIWAUTH */ + (iw_handler) airo_get_auth, /* SIOCGIWAUTH */ + (iw_handler) airo_set_encodeext, /* SIOCSIWENCODEEXT */ + (iw_handler) airo_get_encodeext, /* SIOCGIWENCODEEXT */ + (iw_handler) NULL, /* SIOCSIWPMKSA */ }; /* Note : don't describe AIROIDIFC and AIROOLDIDIFC in here. -- cgit v1.2.3 From f1b50863aa6a96c61a57e3b3a5e76e67b38c5c3e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 30 Jan 2006 13:58:56 -0500 Subject: [PATCH] wireless/ipw2200: support WE-18 WPA enc_capa This patch allows ipw2100 driver to advertise the WPA-related encryption options that it does really support. It's necessary to work correctly with NetworkManager and other programs that actually check driver & card capabilities. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 18e00fe8a21..734d2cb1de0 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -8392,7 +8392,7 @@ static int ipw_wx_get_range(struct net_device *dev, /* Set the Wireless Extension versions */ range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 16; + range->we_version_source = 18; i = 0; if (priv->ieee->mode & (IEEE_B | IEEE_G)) { @@ -8424,6 +8424,9 @@ static int ipw_wx_get_range(struct net_device *dev, IW_EVENT_CAPA_MASK(SIOCGIWAP)); range->event_capa[1] = IW_EVENT_CAPA_K_1; + range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; + IPW_DEBUG_WX("GET Range\n"); return 0; } -- cgit v1.2.3 From fe9313956d67367cc91c5a6989bafc4315801402 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 3 Feb 2006 01:45:12 -0800 Subject: [PATCH] git-netdev-all: s2io fixes Fix this: drivers/built-in.o(.text+0x89469): In function `s2io_get_ethtool_stats': drivers/net/s2io.c:5209: undefined reference to `__udivdi3' Cc: Ravinandan Arakali Cc: Ananda Raju Cc: Adrian Bunk Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 4e392914971..e7a9b0d32a1 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -64,6 +64,7 @@ #include #include #include +#include /* local include */ #include "s2io.h" @@ -5110,6 +5111,7 @@ static void s2io_get_ethtool_stats(struct net_device *dev, int i = 0; nic_t *sp = dev->priv; StatInfo_t *stat_info = sp->mac_control.stats_info; + u64 tmp; s2io_updt_stats(sp); tmp_stats[i++] = @@ -5205,12 +5207,12 @@ static void s2io_get_ethtool_stats(struct net_device *dev, tmp_stats[i++] = stat_info->sw_stat.sending_both; tmp_stats[i++] = stat_info->sw_stat.outof_sequence_pkts; tmp_stats[i++] = stat_info->sw_stat.flush_max_pkts; - if (stat_info->sw_stat.num_aggregations) - tmp_stats[i++] = stat_info->sw_stat.sum_avg_pkts_aggregated / - stat_info->sw_stat.num_aggregations; - else - tmp_stats[i++] = 0; - + tmp = 0; + if (stat_info->sw_stat.num_aggregations) { + tmp = stat_info->sw_stat.sum_avg_pkts_aggregated; + do_div(tmp, stat_info->sw_stat.num_aggregations); + } + tmp_stats[i++] = tmp; } static int s2io_ethtool_get_regs_len(struct net_device *dev) -- cgit v1.2.3 From 79dc190147f8a87718fe72928d5ceb58e09acdb9 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 3 Feb 2006 01:45:13 -0800 Subject: [PATCH] s2io c99 warning fix drivers/net/s2io.c: In function `verify_l3_l4_lro_capable': drivers/net/s2io.c:6638: warning: ISO C90 forbids mixed declarations and code Cc: Ravinandan Arakali Cc: Ananda Raju Cc: Adrian Bunk Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/s2io.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index e7a9b0d32a1..fcce43c9fed 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -6634,9 +6634,10 @@ static void aggregate_new_rx(lro_t *lro, struct iphdr *ip, static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len) { - DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); u8 *ptr; + DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__); + if (!tcp_pyld_len) { /* Runt frame or a pure ack */ return -1; -- cgit v1.2.3 From 4ddc1651cee0143eeddbe043ccd66bb87072e279 Mon Sep 17 00:00:00 2001 From: Jan Niehusmann Date: Sun, 5 Feb 2006 16:13:22 +0100 Subject: [PATCH] let IPW2{1,2}00 select IEEE80211 This patch makes the IPW2100 and IPW2200 options available in the configuration menu even if IEEE80211 has not been selected before. This behaviour is more intuitive for people which are not familiar with the driver internals. The suggestion for this change was made by Alejandro Bonilla Beeche. Signed-off-by: Jan Niehusmann Signed-off-by: Adrian Bunk Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index a1ede41d907..7587df760ec 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -136,8 +136,9 @@ comment "Wireless 802.11b ISA/PCI cards support" config IPW2100 tristate "Intel PRO/Wireless 2100 Network Connection" - depends on NET_RADIO && PCI && IEEE80211 + depends on NET_RADIO && PCI select FW_LOADER + select IEEE80211 ---help--- A driver for the Intel PRO/Wireless 2100 Network Connection 802.11b wireless network adapter. @@ -189,8 +190,9 @@ config IPW2100_DEBUG config IPW2200 tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" - depends on NET_RADIO && IEEE80211 && PCI + depends on NET_RADIO && PCI select FW_LOADER + select IEEE80211 ---help--- A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network Connection adapters. -- cgit v1.2.3 From 4861dd79c1724f37e36d66cc4b3454803aec3f93 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 5 Feb 2006 17:57:36 -0500 Subject: [PATCH] wireless/atmel: convert constants to ieee80211 layer equivalents This patch converts the Atmel driver-only IEEE 802.11 constants to their equivalents from the kernel's ieee80211 layer headers. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/atmel.c | 110 ++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 74 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index dfc24016ba8..87afa6878f2 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -137,44 +137,6 @@ static struct { #define MAC_BOOT_COMPLETE 0x0010 // MAC boot has been completed #define MAC_INIT_OK 0x0002 // MAC boot has been completed -#define C80211_SUBTYPE_MGMT_ASS_REQUEST 0x00 -#define C80211_SUBTYPE_MGMT_ASS_RESPONSE 0x10 -#define C80211_SUBTYPE_MGMT_REASS_REQUEST 0x20 -#define C80211_SUBTYPE_MGMT_REASS_RESPONSE 0x30 -#define C80211_SUBTYPE_MGMT_ProbeRequest 0x40 -#define C80211_SUBTYPE_MGMT_ProbeResponse 0x50 -#define C80211_SUBTYPE_MGMT_BEACON 0x80 -#define C80211_SUBTYPE_MGMT_ATIM 0x90 -#define C80211_SUBTYPE_MGMT_DISASSOSIATION 0xA0 -#define C80211_SUBTYPE_MGMT_Authentication 0xB0 -#define C80211_SUBTYPE_MGMT_Deauthentication 0xC0 - -#define C80211_MGMT_AAN_OPENSYSTEM 0x0000 -#define C80211_MGMT_AAN_SHAREDKEY 0x0001 - -#define C80211_MGMT_CAPABILITY_ESS 0x0001 // see 802.11 p.58 -#define C80211_MGMT_CAPABILITY_IBSS 0x0002 // - " - -#define C80211_MGMT_CAPABILITY_CFPollable 0x0004 // - " - -#define C80211_MGMT_CAPABILITY_CFPollRequest 0x0008 // - " - -#define C80211_MGMT_CAPABILITY_Privacy 0x0010 // - " - - -#define C80211_MGMT_SC_Success 0 -#define C80211_MGMT_SC_Unspecified 1 -#define C80211_MGMT_SC_SupportCapabilities 10 -#define C80211_MGMT_SC_ReassDenied 11 -#define C80211_MGMT_SC_AssDenied 12 -#define C80211_MGMT_SC_AuthAlgNotSupported 13 -#define C80211_MGMT_SC_AuthTransSeqNumError 14 -#define C80211_MGMT_SC_AuthRejectChallenge 15 -#define C80211_MGMT_SC_AuthRejectTimeout 16 -#define C80211_MGMT_SC_AssDeniedHandleAP 17 -#define C80211_MGMT_SC_AssDeniedBSSRate 18 - -#define C80211_MGMT_ElementID_SSID 0 -#define C80211_MGMT_ElementID_SupportedRates 1 -#define C80211_MGMT_ElementID_ChallengeText 16 -#define C80211_MGMT_CAPABILITY_ShortPreamble 0x0020 - #define MIB_MAX_DATA_BYTES 212 #define MIB_HEADER_SIZE 4 /* first four fields */ @@ -2835,7 +2797,7 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 channel) { int rejoin = 0; - int new = capability & C80211_MGMT_CAPABILITY_ShortPreamble ? + int new = capability & MFIE_TYPE_POWER_CONSTRAINT ? SHORT_PREAMBLE : LONG_PREAMBLE; if (priv->preamble != new) { @@ -2921,11 +2883,11 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) memcpy(header.addr2, priv->dev->dev_addr, 6); memcpy(header.addr3, priv->CurrentBSSID, 6); - body.capability = cpu_to_le16(C80211_MGMT_CAPABILITY_ESS); + body.capability = cpu_to_le16(WLAN_CAPABILITY_ESS); if (priv->wep_is_on) - body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_Privacy); + body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); if (priv->preamble == SHORT_PREAMBLE) - body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_ShortPreamble); + body.capability |= cpu_to_le16(MFIE_TYPE_POWER_CONSTRAINT); body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); @@ -2939,10 +2901,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) bodysize = 12 + priv->SSID_size; } - ssid_el_p[0] = C80211_MGMT_ElementID_SSID; + ssid_el_p[0] = MFIE_TYPE_SSID; ssid_el_p[1] = priv->SSID_size; memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); - ssid_el_p[2 + priv->SSID_size] = C80211_MGMT_ElementID_SupportedRates; + ssid_el_p[2 + priv->SSID_size] = MFIE_TYPE_RATES; ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */ memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); @@ -3004,7 +2966,7 @@ static void store_bss_info(struct atmel_private *priv, u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len, u8 *ssid, int is_beacon) { - u8 *bss = capability & C80211_MGMT_CAPABILITY_ESS ? header->addr2 : header->addr3; + u8 *bss = capability & WLAN_CAPABILITY_ESS ? header->addr2 : header->addr3; int i, index; for (index = -1, i = 0; i < priv->BSS_list_entries; i++) @@ -3030,16 +2992,16 @@ static void store_bss_info(struct atmel_private *priv, priv->BSSinfo[index].channel = channel; priv->BSSinfo[index].beacon_period = beacon_period; - priv->BSSinfo[index].UsingWEP = capability & C80211_MGMT_CAPABILITY_Privacy; + priv->BSSinfo[index].UsingWEP = capability & WLAN_CAPABILITY_PRIVACY; memcpy(priv->BSSinfo[index].SSID, ssid, ssid_len); priv->BSSinfo[index].SSIDsize = ssid_len; - if (capability & C80211_MGMT_CAPABILITY_IBSS) + if (capability & WLAN_CAPABILITY_IBSS) priv->BSSinfo[index].BSStype = IW_MODE_ADHOC; - else if (capability & C80211_MGMT_CAPABILITY_ESS) + else if (capability & WLAN_CAPABILITY_ESS) priv->BSSinfo[index].BSStype =IW_MODE_INFRA; - priv->BSSinfo[index].preamble = capability & C80211_MGMT_CAPABILITY_ShortPreamble ? + priv->BSSinfo[index].preamble = capability & MFIE_TYPE_POWER_CONSTRAINT ? SHORT_PREAMBLE : LONG_PREAMBLE; } @@ -3050,7 +3012,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len) u16 trans_seq_no = le16_to_cpu(auth->trans_seq); u16 system = le16_to_cpu(auth->alg); - if (status == C80211_MGMT_SC_Success && !priv->wep_is_on) { + if (status == WLAN_STATUS_SUCCESS && !priv->wep_is_on) { /* no WEP */ if (priv->station_was_associated) { atmel_enter_state(priv, STATION_STATE_REASSOCIATING); @@ -3063,19 +3025,19 @@ static void authenticate(struct atmel_private *priv, u16 frame_len) } } - if (status == C80211_MGMT_SC_Success && priv->wep_is_on) { + if (status == WLAN_STATUS_SUCCESS && priv->wep_is_on) { int should_associate = 0; /* WEP */ if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum) return; - if (system == C80211_MGMT_AAN_OPENSYSTEM) { + if (system == WLAN_AUTH_OPEN) { if (trans_seq_no == 0x0002) { should_associate = 1; } - } else if (system == C80211_MGMT_AAN_SHAREDKEY) { + } else if (system == WLAN_AUTH_SHARED_KEY) { if (trans_seq_no == 0x0002 && - auth->el_id == C80211_MGMT_ElementID_ChallengeText) { + auth->el_id == MFIE_TYPE_CHALLENGE) { send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len); return; } else if (trans_seq_no == 0x0004) { @@ -3140,8 +3102,8 @@ static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) if (frame_len < 8 + rates_len) return; - if (status == C80211_MGMT_SC_Success) { - if (subtype == C80211_SUBTYPE_MGMT_ASS_RESPONSE) + if (status == WLAN_STATUS_SUCCESS) { + if (subtype == IEEE80211_STYPE_ASSOC_RESP) priv->AssociationRequestRetryCnt = 0; else priv->ReAssociationRequestRetryCnt = 0; @@ -3178,9 +3140,9 @@ static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) return; } - if (subtype == C80211_SUBTYPE_MGMT_ASS_RESPONSE && - status != C80211_MGMT_SC_AssDeniedBSSRate && - status != C80211_MGMT_SC_SupportCapabilities && + if (subtype == IEEE80211_STYPE_ASSOC_RESP && + status != WLAN_STATUS_ASSOC_DENIED_RATES && + status != WLAN_STATUS_CAPS_UNSUPPORTED && priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); priv->AssociationRequestRetryCnt++; @@ -3188,9 +3150,9 @@ static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) return; } - if (subtype == C80211_SUBTYPE_MGMT_REASS_RESPONSE && - status != C80211_MGMT_SC_AssDeniedBSSRate && - status != C80211_MGMT_SC_SupportCapabilities && + if (subtype == IEEE80211_STYPE_REASSOC_RESP && + status != WLAN_STATUS_ASSOC_DENIED_RATES && + status != WLAN_STATUS_CAPS_UNSUPPORTED && priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); priv->ReAssociationRequestRetryCnt++; @@ -3325,8 +3287,8 @@ static void atmel_management_frame(struct atmel_private *priv, subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE; switch (subtype) { - case C80211_SUBTYPE_MGMT_BEACON: - case C80211_SUBTYPE_MGMT_ProbeResponse: + case IEEE80211_STYPE_BEACON: + case IEEE80211_STYPE_PROBE_RESP: /* beacon frame has multiple variable-length fields - never let an engineer loose with a data structure design. */ @@ -3384,19 +3346,19 @@ static void atmel_management_frame(struct atmel_private *priv, beacon_interval, channel, rssi, ssid_length, &beacon->rates_el_id, - subtype == C80211_SUBTYPE_MGMT_BEACON); + subtype == IEEE80211_STYPE_BEACON); } break; - case C80211_SUBTYPE_MGMT_Authentication: + case IEEE80211_STYPE_AUTH: if (priv->station_state == STATION_STATE_AUTHENTICATING) authenticate(priv, frame_len); break; - case C80211_SUBTYPE_MGMT_ASS_RESPONSE: - case C80211_SUBTYPE_MGMT_REASS_RESPONSE: + case IEEE80211_STYPE_ASSOC_RESP: + case IEEE80211_STYPE_REASSOC_RESP: if (priv->station_state == STATION_STATE_ASSOCIATING || priv->station_state == STATION_STATE_REASSOCIATING) @@ -3404,7 +3366,7 @@ static void atmel_management_frame(struct atmel_private *priv, break; - case C80211_SUBTYPE_MGMT_DISASSOSIATION: + case IEEE80211_STYPE_DISASSOC: if (priv->station_is_associated && priv->operating_mode == IW_MODE_INFRA && is_frame_from_current_bss(priv, header)) { @@ -3417,7 +3379,7 @@ static void atmel_management_frame(struct atmel_private *priv, break; - case C80211_SUBTYPE_MGMT_Deauthentication: + case IEEE80211_STYPE_DEAUTH: if (priv->operating_mode == IW_MODE_INFRA && is_frame_from_current_bss(priv, header)) { priv->station_was_associated = 0; @@ -3453,12 +3415,12 @@ static void atmel_management_timer(u_long a) priv->AuthenticationRequestRetryCnt = 0; restart_search(priv); } else { - int auth = C80211_MGMT_AAN_OPENSYSTEM; + int auth = WLAN_AUTH_OPEN; priv->AuthenticationRequestRetryCnt++; priv->CurrentAuthentTransactionSeqNum = 0x0001; mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); if (priv->wep_is_on && priv->exclude_unencrypted) - auth = C80211_MGMT_AAN_SHAREDKEY; + auth = WLAN_AUTH_SHARED_KEY; send_authentication_request(priv, auth, NULL, 0); } break; @@ -3558,14 +3520,14 @@ static void atmel_command_irq(struct atmel_private *priv) priv->station_was_associated = priv->station_is_associated; atmel_enter_state(priv, STATION_STATE_READY); } else { - int auth = C80211_MGMT_AAN_OPENSYSTEM; + int auth = WLAN_AUTH_OPEN; priv->AuthenticationRequestRetryCnt = 0; atmel_enter_state(priv, STATION_STATE_AUTHENTICATING); mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); priv->CurrentAuthentTransactionSeqNum = 0x0001; if (priv->wep_is_on && priv->exclude_unencrypted) - auth = C80211_MGMT_AAN_SHAREDKEY; + auth = WLAN_AUTH_SHARED_KEY; send_authentication_request(priv, auth, NULL, 0); } return; -- cgit v1.2.3 From 2c0f63166a5998102ddc7697706af83cbff49317 Mon Sep 17 00:00:00 2001 From: Andreas Happe Date: Thu, 5 Jan 2006 19:40:07 +0100 Subject: [PATCH] ipw2200: add monitor and qos entries to Kconfig I have made a stupid copy&paste error: QoS option is named IPW_QOS not IPW2200_MONITOR. Spotted by Daniel Paschka, thanks. Add the following config entries for the ipw2200 driver to drivers/net/wireless/Kconfig * IPW2200_MONITOR enables Monitor mode * IPW_QOS enables QoS feature - this is under development right now, so it depends upon EXPERIMENTAL Signed-off-by: Andreas Happe Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7587df760ec..f389467f835 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -216,6 +216,19 @@ config IPW2200 say M here and read . The module will be called ipw2200.ko. +config IPW2200_MONITOR + bool "Enable promiscuous mode" + depends on IPW2200 + ---help--- + Enables promiscuous/monitor mode support for the ipw2200 driver. + With this feature compiled into the driver, you can switch to + promiscuous mode via the Wireless Tool's Monitor mode. While in this + mode, no packets can be sent. + +config IPW_QOS + bool "Enable QoS support" + depends on IPW2200 && EXPERIMENTAL + config IPW2200_DEBUG bool "Enable full debugging output in IPW2200 module." depends on IPW2200 -- cgit v1.2.3 From 23afaec4441baf0579fa115b626242d4d23704dd Mon Sep 17 00:00:00 2001 From: Stefan Rompf Date: Tue, 7 Feb 2006 03:42:23 +0800 Subject: [PATCH] ipw2200: Fix WPA network selection problem Do not avoid APs with wpa_ie or rsn_ie if !ieee->wpa_enabled There are broken APs out there that fill these elements even though encryption is disnabled. Also, this breaks legit WEP to WPA migration scenarious. We add a checking to prohibite WPA configured STA trying to associate with non-WPA supported APs. Signed-off-by: Stefan Rompf Signed-off-by: James Ketrenos Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 0702f0eeb78..02d2dae85c4 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -5533,8 +5533,8 @@ static int ipw_best_network(struct ipw_priv *priv, return 0; } - if (!priv->ieee->wpa_enabled && (network->wpa_ie_len > 0 || - network->rsn_ie_len > 0)) { + if (priv->ieee->wpa_enabled && + network->wpa_ie_len == 0 && network->rsn_ie_len == 0) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " "because of WPA capability mismatch.\n", escape_essid(network->ssid, network->ssid_len), -- cgit v1.2.3 From 47c51431fcc5fce3108e8e549cc9d243acd462ed Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Sun, 12 Feb 2006 11:53:04 -0600 Subject: [PATCH] trivial: fix spelling errors in Kconfigs This patch corrects a few spelling and grammar errors found in drivers/net Signed-off-by: Jon Mason Signed-off-by: John W. Linville --- drivers/net/Kconfig | 18 +++++++++--------- drivers/net/arcnet/Kconfig | 4 ++-- drivers/net/irda/Kconfig | 4 ++-- drivers/net/wan/Kconfig | 2 +- drivers/net/wireless/Kconfig | 6 +++--- 5 files changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 47c72a63dfe..2610cedd55c 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -66,7 +66,7 @@ config BONDING 'Trunking' by Sun, 802.3ad by the IEEE, and 'Bonding' in Linux. The driver supports multiple bonding modes to allow for both high - perfomance and high availability operation. + performance and high availability operation. Refer to for more information. @@ -698,8 +698,8 @@ config VORTEX depends on NET_VENDOR_3COM && (PCI || EISA) select MII ---help--- - This option enables driver support for a large number of 10mbps and - 10/100mbps EISA, PCI and PCMCIA 3Com network cards: + This option enables driver support for a large number of 10Mbps and + 10/100Mbps EISA, PCI and PCMCIA 3Com network cards: "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI "Boomerang" (EtherLink XL 3c900 or 3c905) PCI @@ -1021,7 +1021,7 @@ config EEXPRESS_PRO depends on NET_ISA ---help--- If you have a network (Ethernet) card of this type, say Y. This - driver supports intel i82595{FX,TX} based boards. Note however + driver supports Intel i82595{FX,TX} based boards. Note however that the EtherExpress PRO/100 Ethernet card has its own separate driver. Please read the Ethernet-HOWTO, available from . @@ -1207,7 +1207,7 @@ config IBM_EMAC_RX_SKB_HEADROOM help Additional receive skb headroom. Note, that driver will always reserve at least 2 bytes to make IP header - aligned, so usualy there is no need to add any additional + aligned, so usually there is no need to add any additional headroom. If unsure, set to 0. @@ -1933,7 +1933,7 @@ config MYRI_SBUS will be called myri_sbus. This is recommended. config NS83820 - tristate "National Semiconduct DP83820 support" + tristate "National Semiconductor DP83820 support" depends on PCI help This is a driver for the National Semiconductor DP83820 series @@ -2514,7 +2514,7 @@ config PPP_FILTER Say Y here if you want to be able to filter the packets passing over PPP interfaces. This allows you to control which packets count as activity (i.e. which packets will reset the idle timer or bring up - a demand-dialled link) and which packets are to be dropped entirely. + a demand-dialed link) and which packets are to be dropped entirely. You need to say Y here if you wish to use the pass-filter and active-filter options to pppd. @@ -2702,8 +2702,8 @@ config SHAPER for more information. An alternative to this traffic shaper is the experimental - Class-Based Queueing (CBQ) scheduling support which you get if you - say Y to "QoS and/or fair queueing" above. + Class-Based Queuing (CBQ) scheduling support which you get if you + say Y to "QoS and/or fair queuing" above. To compile this driver as a module, choose M here: the module will be called shaper. If unsure, say N. diff --git a/drivers/net/arcnet/Kconfig b/drivers/net/arcnet/Kconfig index 948de2532a1..7284ccad0b9 100644 --- a/drivers/net/arcnet/Kconfig +++ b/drivers/net/arcnet/Kconfig @@ -68,10 +68,10 @@ config ARCNET_CAP packet is stuffed with an extra 4 byte "cookie" which doesn't actually appear on the network. After transmit the driver will send back a packet with protocol byte 0 containing the status of the - transmition: + transmission: 0=no hardware acknowledge 1=excessive nak - 2=transmition accepted by the reciever hardware + 2=transmission accepted by the receiver hardware Received packets are also stuffed with the extra 4 bytes but it will be random data. diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index 7a081346f07..c81fe1c382d 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -283,7 +283,7 @@ config USB_IRDA Say Y here if you want to build support for the USB IrDA FIR Dongle device driver. To compile it as a module, choose M here: the module will be called irda-usb. IrDA-USB support the various IrDA USB - dongles available and most of their pecularities. Those dongles + dongles available and most of their peculiarities. Those dongles plug in the USB port of your computer, are plug and play, and support SIR and FIR (4Mbps) speeds. On the other hand, those dongles tend to be less efficient than a FIR chipset. @@ -360,7 +360,7 @@ config ALI_FIR help Say Y here if you want to build support for the ALi M5123 FIR Controller. The ALi M5123 FIR Controller is embedded in ALi M1543C, - M1535, M1535D, M1535+, M1535D Sourth Bridge. This driver supports + M1535, M1535D, M1535+, M1535D South Bridge. This driver supports SIR, MIR and FIR (4Mbps) speeds. To compile it as a module, choose M here: the module will be called diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 18c27e1e788..883cf7da10f 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -459,7 +459,7 @@ config WANPIPE_FR bool "WANPIPE Frame Relay support" depends on VENDOR_SANGOMA help - Connect a WANPIPE card to a Frame Relay network, or use Frame Felay + Connect a WANPIPE card to a Frame Relay network, or use Frame Relay API to develop custom applications. Contains the Ethernet Bridging over Frame Relay feature, where diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index f389467f835..5b0a19a5058 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -204,7 +204,7 @@ config IPW2200 In order to use this driver, you will need a firmware image for it. You can obtain the firmware from . See the above referenced README.ipw2200 - for information on where to install the firmare images. + for information on where to install the firmware images. You will also very likely need the Wireless Tools in order to configure your card: @@ -262,7 +262,7 @@ config AIRO PCI 802.11 wireless cards. It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - with or without encryption) as well as card before the Cisco - aquisition (Aironet 4500, Aironet 4800, Aironet 4800B). + acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). This driver support both the standard Linux Wireless Extensions and Cisco proprietary API, so both the Linux Wireless Tools and the @@ -411,7 +411,7 @@ config AIRO_CS driver part of the Linux Pcmcia package. It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - with or without encryption) as well as card before the Cisco - aquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also + acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom 802.11b cards. -- cgit v1.2.3 From 1ba61e05e254a587b7a6be9484a8bcd973551be1 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Wed, 15 Feb 2006 13:00:55 +0800 Subject: [PATCH] ipw2200: Fix software crypto shared WEP authentication problem We didn't set the WEP key to hardware when we are using software based crypto. Hardware needs the key to do WEP authentication even for software based encryption. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 02d2dae85c4..30b13a6e6fd 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7061,8 +7061,7 @@ static int ipw_associate_network(struct ipw_priv *priv, priv->assoc_request.auth_type = AUTH_SHARED_KEY; priv->assoc_request.auth_key = priv->ieee->sec.active_key; - if ((priv->ieee->sec.level == SEC_LEVEL_1) && - !(priv->ieee->host_encrypt || priv->ieee->host_decrypt)) + if (priv->ieee->sec.level == SEC_LEVEL_1) ipw_send_wep_keys(priv, DCW_WEP_KEY_SEC_TYPE_WEP); } else if ((priv->capability & CAP_PRIVACY_ON) && -- cgit v1.2.3 From 22d8846e5ce329436628da71a4239ccc2745869f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 5 Feb 2006 18:00:30 -0500 Subject: [PATCH] wireless/airo: fix setting TX key index plus key in ENCODEEXT The previous patch that added ENCODEEXT and AUTH support to the airo driver contained a slight error which would cause setting the TX key index ignore a valid key-set request at the same time. This patch allows any combination of setting the TX key index and setting an encryption key. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index ef6495b0789..b96b6dbe01f 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -6266,7 +6266,7 @@ static int airo_set_encodeext(struct net_device *dev, CapabilityRid cap_rid; /* Card capability info */ int perm = ( encoding->flags & IW_ENCODE_TEMP ? 0 : 1 ); u16 currentAuthType = local->config.authType; - int idx, key_len, alg = ext->alg; /* Check encryption mode */ + int idx, key_len, alg = ext->alg, set_key = 1; wep_key_t key; /* Is WEP supported ? */ @@ -6289,10 +6289,15 @@ static int airo_set_encodeext(struct net_device *dev, if (encoding->flags & IW_ENCODE_DISABLED) alg = IW_ENCODE_ALG_NONE; - /* Just setting the transmit key? */ if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { + /* Only set transmit key index here, actual + * key is set below if needed. + */ set_wep_key(local, idx, NULL, 0, perm, 1); - } else { + set_key = ext->key_len > 0 ? 1 : 0; + } + + if (set_key) { /* Set the requested key first */ memset(key.key, 0, MAX_KEY_SIZE); switch (alg) { -- cgit v1.2.3 From ee407b02f3f1992bc746876c26f8175c8783562b Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Sat, 4 Feb 2006 13:13:17 -0500 Subject: [PATCH] forcedeth: Add vlan support This forcedeth patch adds support for vlan stripping/inserting in hardware. Signed-off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 76 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 3682ec61e8a..0fbe342c2ac 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -102,6 +102,7 @@ * 0.47: 26 Oct 2005: Add phyaddr 0 in phy scan. * 0.48: 24 Dec 2005: Disable TSO, bugfix for pci_map_single * 0.49: 10 Dec 2005: Fix tso for large buffers. + * 0.50: 20 Jan 2006: Add 8021pq tagging support. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -113,7 +114,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.49" +#define FORCEDETH_VERSION "0.50" #define DRV_NAME "forcedeth" #include @@ -153,6 +154,7 @@ #define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */ #define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */ #define DEV_HAS_CHECKSUM 0x0010 /* device supports tx and rx checksum offloads */ +#define DEV_HAS_VLAN 0x0020 /* device supports vlan tagging and striping */ enum { NvRegIrqStatus = 0x000, @@ -254,6 +256,8 @@ enum { #define NVREG_TXRXCTL_DESC_1 0 #define NVREG_TXRXCTL_DESC_2 0x02100 #define NVREG_TXRXCTL_DESC_3 0x02200 +#define NVREG_TXRXCTL_VLANSTRIP 0x00040 +#define NVREG_TXRXCTL_VLANINS 0x00080 NvRegMIIStatus = 0x180, #define NVREG_MIISTAT_ERROR 0x0001 #define NVREG_MIISTAT_LINKCHANGE 0x0008 @@ -303,6 +307,8 @@ enum { #define NVREG_POWERSTATE_D1 0x0001 #define NVREG_POWERSTATE_D2 0x0002 #define NVREG_POWERSTATE_D3 0x0003 + NvRegVlanControl = 0x300, +#define NVREG_VLANCONTROL_ENABLE 0x2000 }; /* Big endian: should work, but is untested */ @@ -314,7 +320,7 @@ struct ring_desc { struct ring_desc_ex { u32 PacketBufferHigh; u32 PacketBufferLow; - u32 Reserved; + u32 TxVlan; u32 FlagLen; }; @@ -355,6 +361,8 @@ typedef union _ring_type { #define NV_TX2_CHECKSUM_L3 (1<<27) #define NV_TX2_CHECKSUM_L4 (1<<26) +#define NV_TX3_VLAN_TAG_PRESENT (1<<18) + #define NV_RX_DESCRIPTORVALID (1<<16) #define NV_RX_MISSEDFRAME (1<<17) #define NV_RX_SUBSTRACT1 (1<<18) @@ -385,6 +393,9 @@ typedef union _ring_type { #define NV_RX2_ERROR (1<<30) #define NV_RX2_AVAIL (1<<31) +#define NV_RX3_VLAN_TAG_PRESENT (1<<16) +#define NV_RX3_VLAN_TAG_MASK (0x0000FFFF) + /* Miscelaneous hardware related defines: */ #define NV_PCI_REGSZ 0x270 @@ -511,6 +522,7 @@ struct fe_priv { u32 irqmask; u32 desc_ver; u32 txrxctl_bits; + u32 vlanctl_bits; void __iomem *base; @@ -540,6 +552,9 @@ struct fe_priv { dma_addr_t tx_dma[TX_RING]; unsigned int tx_dma_len[TX_RING]; u32 tx_flags; + + /* vlan fields */ + struct vlan_group *vlangrp; }; /* @@ -1031,6 +1046,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) u32 bcnt; u32 size = skb->len-skb->data_len; u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + u32 tx_flags_vlan = 0; /* add fragments to entries count */ for (i = 0; i < fragments; i++) { @@ -1111,10 +1127,16 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) #endif tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); + /* vlan tag */ + if (np->vlangrp && vlan_tx_tag_present(skb)) { + tx_flags_vlan = NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb); + } + /* set tx flags */ if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); } else { + np->tx_ring.ex[start_nr].TxVlan = cpu_to_le32(tx_flags_vlan); np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); } @@ -1342,6 +1364,8 @@ static void nv_rx_process(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u32 Flags; + u32 vlanflags = 0; + for (;;) { struct sk_buff *skb; @@ -1357,6 +1381,7 @@ static void nv_rx_process(struct net_device *dev) } else { Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen); len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver); + vlanflags = le32_to_cpu(np->rx_ring.ex[i].PacketBufferLow); } dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n", @@ -1474,7 +1499,11 @@ static void nv_rx_process(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n", dev->name, np->cur_rx, len, skb->protocol); - netif_rx(skb); + if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) { + vlan_hwaccel_rx(skb, np->vlangrp, vlanflags & NV_RX3_VLAN_TAG_MASK); + } else { + netif_rx(skb); + } dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += len; @@ -2217,6 +2246,34 @@ static struct ethtool_ops ops = { .get_perm_addr = ethtool_op_get_perm_addr, }; +static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) +{ + struct fe_priv *np = get_nvpriv(dev); + + spin_lock_irq(&np->lock); + + /* save vlan group */ + np->vlangrp = grp; + + if (grp) { + /* enable vlan on MAC */ + np->txrxctl_bits |= NVREG_TXRXCTL_VLANSTRIP | NVREG_TXRXCTL_VLANINS; + } else { + /* disable vlan on MAC */ + np->txrxctl_bits &= ~NVREG_TXRXCTL_VLANSTRIP; + np->txrxctl_bits &= ~NVREG_TXRXCTL_VLANINS; + } + + writel(np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); + + spin_unlock_irq(&np->lock); +}; + +static void nv_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) +{ + /* nothing to do */ +}; + static int nv_open(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); @@ -2265,6 +2322,7 @@ static int nv_open(struct net_device *dev) writel(np->linkspeed, base + NvRegLinkSpeed); writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3); writel(np->txrxctl_bits, base + NvRegTxRxControl); + writel(np->vlanctl_bits, base + NvRegVlanControl); pci_push(base); writel(NVREG_TXRXCTL_BIT1|np->txrxctl_bits, base + NvRegTxRxControl); reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, @@ -2496,6 +2554,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i #endif } + np->vlanctl_bits = 0; + if (id->driver_data & DEV_HAS_VLAN) { + np->vlanctl_bits = NVREG_VLANCONTROL_ENABLE; + dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX; + dev->vlan_rx_register = nv_vlan_rx_register; + dev->vlan_rx_kill_vid = nv_vlan_rx_kill_vid; + } + err = -ENOMEM; np->base = ioremap(addr, NV_PCI_REGSZ); if (!np->base) @@ -2737,11 +2803,11 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN, }, {0,}, }; -- cgit v1.2.3 From 0832b25a75d128e4f9724156380ba071c4f3f20d Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Sat, 4 Feb 2006 13:13:26 -0500 Subject: [PATCH] forcedeth: Add support for 64bit rings This forcedeth patch adds high dma support for tx/rx rings. Signed-off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 58 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 0fbe342c2ac..870613bf3fd 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -103,6 +103,7 @@ * 0.48: 24 Dec 2005: Disable TSO, bugfix for pci_map_single * 0.49: 10 Dec 2005: Fix tso for large buffers. * 0.50: 20 Jan 2006: Add 8021pq tagging support. + * 0.51: 20 Jan 2006: Add 64bit consistent memory allocation for rings. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -114,7 +115,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.50" +#define FORCEDETH_VERSION "0.51" #define DRV_NAME "forcedeth" #include @@ -258,6 +259,8 @@ enum { #define NVREG_TXRXCTL_DESC_3 0x02200 #define NVREG_TXRXCTL_VLANSTRIP 0x00040 #define NVREG_TXRXCTL_VLANINS 0x00080 + NvRegTxRingPhysAddrHigh = 0x148, + NvRegRxRingPhysAddrHigh = 0x14C, NvRegMIIStatus = 0x180, #define NVREG_MIISTAT_ERROR 0x0001 #define NVREG_MIISTAT_LINKCHANGE 0x0008 @@ -627,6 +630,33 @@ static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target, return 0; } +#define NV_SETUP_RX_RING 0x01 +#define NV_SETUP_TX_RING 0x02 + +static void setup_hw_rings(struct net_device *dev, int rxtx_flags) +{ + struct fe_priv *np = get_nvpriv(dev); + u8 __iomem *base = get_hwbase(dev); + + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + if (rxtx_flags & NV_SETUP_RX_RING) { + writel((u32) cpu_to_le64(np->ring_addr), base + NvRegRxRingPhysAddr); + } + if (rxtx_flags & NV_SETUP_TX_RING) { + writel((u32) cpu_to_le64(np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + } + } else { + if (rxtx_flags & NV_SETUP_RX_RING) { + writel((u32) cpu_to_le64(np->ring_addr), base + NvRegRxRingPhysAddr); + writel((u32) (cpu_to_le64(np->ring_addr) >> 32), base + NvRegRxRingPhysAddrHigh); + } + if (rxtx_flags & NV_SETUP_TX_RING) { + writel((u32) cpu_to_le64(np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); + writel((u32) (cpu_to_le64(np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)) >> 32), base + NvRegTxRingPhysAddrHigh); + } + } +} + #define MII_READ (-1) /* mii_rw: read/write a register on the PHY. * @@ -1295,10 +1325,7 @@ static void nv_tx_timeout(struct net_device *dev) printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name); nv_drain_tx(dev); np->next_tx = np->nic_tx = 0; - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); - else - writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); + setup_hw_rings(dev, NV_SETUP_TX_RING); netif_wake_queue(dev); } @@ -1573,11 +1600,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) } /* reinit nic view of the rx queue */ writel(np->rx_buf_sz, base + NvRegOffloadConfig); - writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); - else - writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); + setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING); writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes); pci_push(base); @@ -2310,11 +2333,7 @@ static int nv_open(struct net_device *dev) nv_copy_mac_to_hw(dev); /* 4) give hw rings */ - writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); - if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) - writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); - else - writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); + setup_hw_rings(dev, NV_SETUP_RX_RING | NV_SETUP_TX_RING); writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes); @@ -2529,7 +2548,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n", pci_name(pci_dev)); } else { - dev->features |= NETIF_F_HIGHDMA; + if (pci_set_consistent_dma_mask(pci_dev, 0x0000007fffffffffULL)) { + printk(KERN_INFO "forcedeth: 64-bit DMA (consistent) failed for device %s.\n", + pci_name(pci_dev)); + goto out_relreg; + } else { + dev->features |= NETIF_F_HIGHDMA; + printk(KERN_INFO "forcedeth: using HIGHDMA\n"); + } } np->txrxctl_bits = NVREG_TXRXCTL_DESC_3; } else if (id->driver_data & DEV_HAS_LARGEDESC) { -- cgit v1.2.3 From d33a73c81241e3d9ab8da2d0558429bdd5b4ef9a Mon Sep 17 00:00:00 2001 From: Ayaz Abdulla Date: Sat, 4 Feb 2006 13:13:31 -0500 Subject: [PATCH] forcedeth: Add support for MSI/MSIX This forcedeth patch adds support for MSI/MSIX interrupts. Signed-off-By: Ayaz Abdulla Signed-off-by: Jeff Garzik --- drivers/net/forcedeth.c | 467 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 436 insertions(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 870613bf3fd..e7fc28b07e5 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -104,6 +104,7 @@ * 0.49: 10 Dec 2005: Fix tso for large buffers. * 0.50: 20 Jan 2006: Add 8021pq tagging support. * 0.51: 20 Jan 2006: Add 64bit consistent memory allocation for rings. + * 0.52: 20 Jan 2006: Add MSI/MSIX support. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -115,7 +116,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.51" +#define FORCEDETH_VERSION "0.52" #define DRV_NAME "forcedeth" #include @@ -156,6 +157,8 @@ #define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */ #define DEV_HAS_CHECKSUM 0x0010 /* device supports tx and rx checksum offloads */ #define DEV_HAS_VLAN 0x0020 /* device supports vlan tagging and striping */ +#define DEV_HAS_MSI 0x0040 /* device supports MSI */ +#define DEV_HAS_MSI_X 0x0080 /* device supports MSI-X */ enum { NvRegIrqStatus = 0x000, @@ -169,14 +172,17 @@ enum { #define NVREG_IRQ_TX_OK 0x0010 #define NVREG_IRQ_TIMER 0x0020 #define NVREG_IRQ_LINK 0x0040 -#define NVREG_IRQ_TX_ERROR 0x0080 -#define NVREG_IRQ_TX1 0x0100 +#define NVREG_IRQ_RX_FORCED 0x0080 +#define NVREG_IRQ_TX_FORCED 0x0100 #define NVREG_IRQMASK_THROUGHPUT 0x00df #define NVREG_IRQMASK_CPU 0x0040 +#define NVREG_IRQ_TX_ALL (NVREG_IRQ_TX_ERR|NVREG_IRQ_TX_OK|NVREG_IRQ_TX_FORCED) +#define NVREG_IRQ_RX_ALL (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_RX_FORCED) +#define NVREG_IRQ_OTHER (NVREG_IRQ_TIMER|NVREG_IRQ_LINK) #define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \ - NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX_ERROR| \ - NVREG_IRQ_TX1)) + NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_RX_FORCED| \ + NVREG_IRQ_TX_FORCED)) NvRegUnknownSetupReg6 = 0x008, #define NVREG_UNKSETUP6_VAL 3 @@ -188,6 +194,10 @@ enum { NvRegPollingInterval = 0x00c, #define NVREG_POLL_DEFAULT_THROUGHPUT 970 #define NVREG_POLL_DEFAULT_CPU 13 + NvRegMSIMap0 = 0x020, + NvRegMSIMap1 = 0x024, + NvRegMSIIrqMask = 0x030, +#define NVREG_MSI_VECTOR_0_ENABLED 0x01 NvRegMisc1 = 0x080, #define NVREG_MISC1_HD 0x02 #define NVREG_MISC1_FORCE 0x3b0f3c @@ -312,6 +322,9 @@ enum { #define NVREG_POWERSTATE_D3 0x0003 NvRegVlanControl = 0x300, #define NVREG_VLANCONTROL_ENABLE 0x2000 + NvRegMSIXMap0 = 0x3e0, + NvRegMSIXMap1 = 0x3e4, + NvRegMSIXIrqStatus = 0x3f0, }; /* Big endian: should work, but is untested */ @@ -489,6 +502,18 @@ typedef union _ring_type { #define LPA_1000FULL 0x0800 #define LPA_1000HALF 0x0400 +/* MSI/MSI-X defines */ +#define NV_MSI_X_MAX_VECTORS 8 +#define NV_MSI_X_VECTORS_MASK 0x000f +#define NV_MSI_CAPABLE 0x0010 +#define NV_MSI_X_CAPABLE 0x0020 +#define NV_MSI_ENABLED 0x0040 +#define NV_MSI_X_ENABLED 0x0080 + +#define NV_MSI_X_VECTOR_ALL 0x0 +#define NV_MSI_X_VECTOR_RX 0x0 +#define NV_MSI_X_VECTOR_TX 0x1 +#define NV_MSI_X_VECTOR_OTHER 0x2 /* * SMP locking: @@ -540,6 +565,7 @@ struct fe_priv { unsigned int pkt_limit; struct timer_list oom_kick; struct timer_list nic_poll; + u32 nic_poll_irq; /* media detection workaround. * Locking: Within irq hander or disable_irq+spin_lock(&np->lock); @@ -558,6 +584,10 @@ struct fe_priv { /* vlan fields */ struct vlan_group *vlangrp; + + /* msi/msi-x fields */ + u32 msi_flags; + struct msix_entry msi_x_entry[NV_MSI_X_MAX_VECTORS]; }; /* @@ -585,6 +615,16 @@ static int optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT; */ static int poll_interval = -1; +/* + * Disable MSI interrupts + */ +static int disable_msi = 0; + +/* + * Disable MSIX interrupts + */ +static int disable_msix = 0; + static inline struct fe_priv *get_nvpriv(struct net_device *dev) { return netdev_priv(dev); @@ -948,14 +988,27 @@ static void nv_do_rx_refill(unsigned long data) struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); - disable_irq(dev->irq); + + if (!(np->msi_flags & NV_MSI_X_ENABLED) || + ((np->msi_flags & NV_MSI_X_ENABLED) && + ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { + disable_irq(dev->irq); + } else { + disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); + } if (nv_alloc_rx(dev)) { spin_lock(&np->lock); if (!np->in_shutdown) mod_timer(&np->oom_kick, jiffies + OOM_REFILL); spin_unlock(&np->lock); } - enable_irq(dev->irq); + if (!(np->msi_flags & NV_MSI_X_ENABLED) || + ((np->msi_flags & NV_MSI_X_ENABLED) && + ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { + enable_irq(dev->irq); + } else { + enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); + } } static void nv_init_rx(struct net_device *dev) @@ -1010,7 +1063,7 @@ static int nv_release_txskb(struct net_device *dev, unsigned int skbnr) } if (np->tx_skbuff[skbnr]) { - dev_kfree_skb_irq(np->tx_skbuff[skbnr]); + dev_kfree_skb_any(np->tx_skbuff[skbnr]); np->tx_skbuff[skbnr] = NULL; return 1; } else { @@ -1261,9 +1314,14 @@ static void nv_tx_timeout(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); + u32 status; + + if (np->msi_flags & NV_MSI_X_ENABLED) + status = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; + else + status = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; - printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name, - readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK); + printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name, status); { int i; @@ -1579,7 +1637,15 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) * guessed, there is probably a simpler approach. * Changing the MTU is a rare event, it shouldn't matter. */ - disable_irq(dev->irq); + if (!(np->msi_flags & NV_MSI_X_ENABLED) || + ((np->msi_flags & NV_MSI_X_ENABLED) && + ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { + disable_irq(dev->irq); + } else { + disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); + disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); + disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); + } spin_lock_bh(&dev->xmit_lock); spin_lock(&np->lock); /* stop engines */ @@ -1612,7 +1678,15 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu) nv_start_tx(dev); spin_unlock(&np->lock); spin_unlock_bh(&dev->xmit_lock); - enable_irq(dev->irq); + if (!(np->msi_flags & NV_MSI_X_ENABLED) || + ((np->msi_flags & NV_MSI_X_ENABLED) && + ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { + enable_irq(dev->irq); + } else { + enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); + enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); + enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); + } } return 0; } @@ -1918,8 +1992,13 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name); for (i=0; ; i++) { - events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; - writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + if (!(np->msi_flags & NV_MSI_X_ENABLED)) { + events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK; + writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); + } else { + events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK; + writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus); + } pci_push(base); dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); if (!(events & np->irqmask)) @@ -1959,11 +2038,16 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) if (i > max_interrupt_work) { spin_lock(&np->lock); /* disable interrupts on the nic */ - writel(0, base + NvRegIrqMask); + if (!(np->msi_flags & NV_MSI_X_ENABLED)) + writel(0, base + NvRegIrqMask); + else + writel(np->irqmask, base + NvRegIrqMask); pci_push(base); - if (!np->in_shutdown) + if (!np->in_shutdown) { + np->nic_poll_irq = np->irqmask; mod_timer(&np->nic_poll, jiffies + POLL_WAIT); + } printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i); spin_unlock(&np->lock); break; @@ -1975,22 +2059,212 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) return IRQ_RETVAL(i); } +static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + u32 events; + int i; + + dprintk(KERN_DEBUG "%s: nv_nic_irq_tx\n", dev->name); + + for (i=0; ; i++) { + events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL; + writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus); + pci_push(base); + dprintk(KERN_DEBUG "%s: tx irq: %08x\n", dev->name, events); + if (!(events & np->irqmask)) + break; + + spin_lock(&np->lock); + nv_tx_done(dev); + spin_unlock(&np->lock); + + if (events & (NVREG_IRQ_TX_ERR)) { + dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n", + dev->name, events); + } + if (i > max_interrupt_work) { + spin_lock(&np->lock); + /* disable interrupts on the nic */ + writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask); + pci_push(base); + + if (!np->in_shutdown) { + np->nic_poll_irq |= NVREG_IRQ_TX_ALL; + mod_timer(&np->nic_poll, jiffies + POLL_WAIT); + } + printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i); + spin_unlock(&np->lock); + break; + } + + } + dprintk(KERN_DEBUG "%s: nv_nic_irq_tx completed\n", dev->name); + + return IRQ_RETVAL(i); +} + +static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + u32 events; + int i; + + dprintk(KERN_DEBUG "%s: nv_nic_irq_rx\n", dev->name); + + for (i=0; ; i++) { + events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL; + writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); + pci_push(base); + dprintk(KERN_DEBUG "%s: rx irq: %08x\n", dev->name, events); + if (!(events & np->irqmask)) + break; + + nv_rx_process(dev); + if (nv_alloc_rx(dev)) { + spin_lock(&np->lock); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + spin_unlock(&np->lock); + } + + if (i > max_interrupt_work) { + spin_lock(&np->lock); + /* disable interrupts on the nic */ + writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); + pci_push(base); + + if (!np->in_shutdown) { + np->nic_poll_irq |= NVREG_IRQ_RX_ALL; + mod_timer(&np->nic_poll, jiffies + POLL_WAIT); + } + printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i); + spin_unlock(&np->lock); + break; + } + + } + dprintk(KERN_DEBUG "%s: nv_nic_irq_rx completed\n", dev->name); + + return IRQ_RETVAL(i); +} + +static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) data; + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + u32 events; + int i; + + dprintk(KERN_DEBUG "%s: nv_nic_irq_other\n", dev->name); + + for (i=0; ; i++) { + events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_OTHER; + writel(NVREG_IRQ_OTHER, base + NvRegMSIXIrqStatus); + pci_push(base); + dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events); + if (!(events & np->irqmask)) + break; + + if (events & NVREG_IRQ_LINK) { + spin_lock(&np->lock); + nv_link_irq(dev); + spin_unlock(&np->lock); + } + if (np->need_linktimer && time_after(jiffies, np->link_timeout)) { + spin_lock(&np->lock); + nv_linkchange(dev); + spin_unlock(&np->lock); + np->link_timeout = jiffies + LINK_TIMEOUT; + } + if (events & (NVREG_IRQ_UNKNOWN)) { + printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n", + dev->name, events); + } + if (i > max_interrupt_work) { + spin_lock(&np->lock); + /* disable interrupts on the nic */ + writel(NVREG_IRQ_OTHER, base + NvRegIrqMask); + pci_push(base); + + if (!np->in_shutdown) { + np->nic_poll_irq |= NVREG_IRQ_OTHER; + mod_timer(&np->nic_poll, jiffies + POLL_WAIT); + } + printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i); + spin_unlock(&np->lock); + break; + } + + } + dprintk(KERN_DEBUG "%s: nv_nic_irq_other completed\n", dev->name); + + return IRQ_RETVAL(i); +} + static void nv_do_nic_poll(unsigned long data) { struct net_device *dev = (struct net_device *) data; struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); + u32 mask = 0; - disable_irq(dev->irq); - /* FIXME: Do we need synchronize_irq(dev->irq) here? */ /* + * First disable irq(s) and then * reenable interrupts on the nic, we have to do this before calling * nv_nic_irq because that may decide to do otherwise */ - writel(np->irqmask, base + NvRegIrqMask); + + if (!(np->msi_flags & NV_MSI_X_ENABLED) || + ((np->msi_flags & NV_MSI_X_ENABLED) && + ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { + disable_irq(dev->irq); + mask = np->irqmask; + } else { + if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) { + disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); + mask |= NVREG_IRQ_RX_ALL; + } + if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) { + disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); + mask |= NVREG_IRQ_TX_ALL; + } + if (np->nic_poll_irq & NVREG_IRQ_OTHER) { + disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); + mask |= NVREG_IRQ_OTHER; + } + } + np->nic_poll_irq = 0; + + /* FIXME: Do we need synchronize_irq(dev->irq) here? */ + + writel(mask, base + NvRegIrqMask); pci_push(base); - nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL); - enable_irq(dev->irq); + + if (!(np->msi_flags & NV_MSI_X_ENABLED) || + ((np->msi_flags & NV_MSI_X_ENABLED) && + ((np->msi_flags & NV_MSI_X_VECTORS_MASK) == 0x1))) { + nv_nic_irq((int) 0, (void *) data, (struct pt_regs *) NULL); + enable_irq(dev->irq); + } else { + if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) { + nv_nic_irq_rx((int) 0, (void *) data, (struct pt_regs *) NULL); + enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); + } + if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) { + nv_nic_irq_tx((int) 0, (void *) data, (struct pt_regs *) NULL); + enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); + } + if (np->nic_poll_irq & NVREG_IRQ_OTHER) { + nv_nic_irq_other((int) 0, (void *) data, (struct pt_regs *) NULL); + enable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); + } + } } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -2297,11 +2571,38 @@ static void nv_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) /* nothing to do */ }; +static void set_msix_vector_map(struct net_device *dev, u32 vector, u32 irqmask) +{ + u8 __iomem *base = get_hwbase(dev); + int i; + u32 msixmap = 0; + + /* Each interrupt bit can be mapped to a MSIX vector (4 bits). + * MSIXMap0 represents the first 8 interrupts and MSIXMap1 represents + * the remaining 8 interrupts. + */ + for (i = 0; i < 8; i++) { + if ((irqmask >> i) & 0x1) { + msixmap |= vector << (i << 2); + } + } + writel(readl(base + NvRegMSIXMap0) | msixmap, base + NvRegMSIXMap0); + + msixmap = 0; + for (i = 0; i < 8; i++) { + if ((irqmask >> (i + 8)) & 0x1) { + msixmap |= vector << (i << 2); + } + } + writel(readl(base + NvRegMSIXMap1) | msixmap, base + NvRegMSIXMap1); +} + static int nv_open(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base = get_hwbase(dev); - int ret, oom, i; + int ret = 1; + int oom, i; dprintk(KERN_DEBUG "nv_open: begin\n"); @@ -2392,9 +2693,77 @@ static int nv_open(struct net_device *dev) writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus); pci_push(base); - ret = request_irq(dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev); - if (ret) - goto out_drain; + if (np->msi_flags & NV_MSI_X_CAPABLE) { + for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) { + np->msi_x_entry[i].entry = i; + } + if ((ret = pci_enable_msix(np->pci_dev, np->msi_x_entry, (np->msi_flags & NV_MSI_X_VECTORS_MASK))) == 0) { + np->msi_flags |= NV_MSI_X_ENABLED; + if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT) { + /* Request irq for rx handling */ + if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, &nv_nic_irq_rx, SA_SHIRQ, dev->name, dev) != 0) { + printk(KERN_INFO "forcedeth: request_irq failed for rx %d\n", ret); + pci_disable_msix(np->pci_dev); + np->msi_flags &= ~NV_MSI_X_ENABLED; + goto out_drain; + } + /* Request irq for tx handling */ + if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, &nv_nic_irq_tx, SA_SHIRQ, dev->name, dev) != 0) { + printk(KERN_INFO "forcedeth: request_irq failed for tx %d\n", ret); + pci_disable_msix(np->pci_dev); + np->msi_flags &= ~NV_MSI_X_ENABLED; + goto out_drain; + } + /* Request irq for link and timer handling */ + if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, &nv_nic_irq_other, SA_SHIRQ, dev->name, dev) != 0) { + printk(KERN_INFO "forcedeth: request_irq failed for link %d\n", ret); + pci_disable_msix(np->pci_dev); + np->msi_flags &= ~NV_MSI_X_ENABLED; + goto out_drain; + } + + /* map interrupts to their respective vector */ + writel(0, base + NvRegMSIXMap0); + writel(0, base + NvRegMSIXMap1); + set_msix_vector_map(dev, NV_MSI_X_VECTOR_RX, NVREG_IRQ_RX_ALL); + set_msix_vector_map(dev, NV_MSI_X_VECTOR_TX, NVREG_IRQ_TX_ALL); + set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER); + } else { + /* Request irq for all interrupts */ + if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) { + printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret); + pci_disable_msix(np->pci_dev); + np->msi_flags &= ~NV_MSI_X_ENABLED; + goto out_drain; + } + + /* map interrupts to vector 0 */ + writel(0, base + NvRegMSIXMap0); + writel(0, base + NvRegMSIXMap1); + } + } + } + if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) { + if ((ret = pci_enable_msi(np->pci_dev)) == 0) { + np->msi_flags |= NV_MSI_ENABLED; + if (request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) { + printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret); + pci_disable_msi(np->pci_dev); + np->msi_flags &= ~NV_MSI_ENABLED; + goto out_drain; + } + + /* map interrupts to vector 0 */ + writel(0, base + NvRegMSIMap0); + writel(0, base + NvRegMSIMap1); + /* enable msi vector 0 */ + writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask); + } + } + if (ret != 0) { + if (request_irq(np->pci_dev->irq, &nv_nic_irq, SA_SHIRQ, dev->name, dev) != 0) + goto out_drain; + } /* ask for interrupts */ writel(np->irqmask, base + NvRegIrqMask); @@ -2441,6 +2810,7 @@ static int nv_close(struct net_device *dev) { struct fe_priv *np = netdev_priv(dev); u8 __iomem *base; + int i; spin_lock_irq(&np->lock); np->in_shutdown = 1; @@ -2458,13 +2828,31 @@ static int nv_close(struct net_device *dev) /* disable interrupts on the nic or we will lock up */ base = get_hwbase(dev); - writel(0, base + NvRegIrqMask); + if (np->msi_flags & NV_MSI_X_ENABLED) { + writel(np->irqmask, base + NvRegIrqMask); + } else { + if (np->msi_flags & NV_MSI_ENABLED) + writel(0, base + NvRegMSIIrqMask); + writel(0, base + NvRegIrqMask); + } pci_push(base); dprintk(KERN_INFO "%s: Irqmask is zero again\n", dev->name); spin_unlock_irq(&np->lock); - free_irq(dev->irq, dev); + if (np->msi_flags & NV_MSI_X_ENABLED) { + for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) { + free_irq(np->msi_x_entry[i].vector, dev); + } + pci_disable_msix(np->pci_dev); + np->msi_flags &= ~NV_MSI_X_ENABLED; + } else { + free_irq(np->pci_dev->irq, dev); + if (np->msi_flags & NV_MSI_ENABLED) { + pci_disable_msi(np->pci_dev); + np->msi_flags &= ~NV_MSI_ENABLED; + } + } drain_ring(dev); @@ -2588,6 +2976,14 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i dev->vlan_rx_kill_vid = nv_vlan_rx_kill_vid; } + np->msi_flags = 0; + if ((id->driver_data & DEV_HAS_MSI) && !disable_msi) { + np->msi_flags |= NV_MSI_CAPABLE; + } + if ((id->driver_data & DEV_HAS_MSI_X) && !disable_msix) { + np->msi_flags |= NV_MSI_X_CAPABLE; + } + err = -ENOMEM; np->base = ioremap(addr, NV_PCI_REGSZ); if (!np->base) @@ -2670,10 +3066,15 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i } else { np->tx_flags = NV_TX2_VALID; } - if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT) + if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT) { np->irqmask = NVREG_IRQMASK_THROUGHPUT; - else + if (np->msi_flags & NV_MSI_X_CAPABLE) /* set number of vectors */ + np->msi_flags |= 0x0003; + } else { np->irqmask = NVREG_IRQMASK_CPU; + if (np->msi_flags & NV_MSI_X_CAPABLE) /* set number of vectors */ + np->msi_flags |= 0x0001; + } if (id->driver_data & DEV_NEED_TIMERIRQ) np->irqmask |= NVREG_IRQ_TIMER; @@ -2829,11 +3230,11 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X, }, { /* MCP55 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN, + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X, }, {0,}, }; @@ -2863,6 +3264,10 @@ module_param(optimization_mode, int, 0); MODULE_PARM_DESC(optimization_mode, "In throughput mode (0), every tx & rx packet will generate an interrupt. In CPU mode (1), interrupts are controlled by a timer."); module_param(poll_interval, int, 0); MODULE_PARM_DESC(poll_interval, "Interval determines how frequent timer interrupt is generated by [(time_in_micro_secs * 100) / (2^10)]. Min is 0 and Max is 65535."); +module_param(disable_msi, int, 0); +MODULE_PARM_DESC(disable_msi, "Disable MSI interrupts by setting to 1."); +module_param(disable_msix, int, 0); +MODULE_PARM_DESC(disable_msix, "Disable MSIX interrupts by setting to 1."); MODULE_AUTHOR("Manfred Spraul "); MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver"); -- cgit v1.2.3 From a23f460dd0c7c9c58b03494c7819e126b2c72383 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 27 Feb 2006 16:28:36 -0500 Subject: [PATCH] wireless/airo: Remove 'Setting transmit key' info messages These messages end up polluting logs when things like NetworkManager or wpa_supplicant are controlling the driver. They aren't really that useful, and no other drivers output messages like this when the user fiddles with encryption keys. Users can use iwconfig and other wireless-tools methods to determine and change the current transmit key if they wish to do so manually. Therefore, remove the messages. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index b96b6dbe01f..864937a409e 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -5036,7 +5036,6 @@ static int set_wep_key(struct airo_info *ai, u16 index, wkr.len = sizeof(wkr); wkr.kindex = 0xffff; wkr.mac[0] = (char)index; - if (perm) printk(KERN_INFO "Setting transmit key to %d\n", index); if (perm) ai->defindex = (char)index; } else { // We are actually setting the key @@ -5045,7 +5044,6 @@ static int set_wep_key(struct airo_info *ai, u16 index, wkr.klen = keylen; memcpy( wkr.key, key, keylen ); memcpy( wkr.mac, macaddr, ETH_ALEN ); - printk(KERN_INFO "Setting key %d\n", index); } if (perm) disable_MAC(ai, lock); -- cgit v1.2.3 From c1605eb37aa658b810a5a7080412d656ddce2f76 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:16:38 -0800 Subject: e1000: Remove Multiqueue code until we have support for MSI-X in our hardware Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000.h | 26 ----- drivers/net/e1000/e1000_ethtool.c | 43 -------- drivers/net/e1000/e1000_main.c | 227 +------------------------------------- 3 files changed, 4 insertions(+), 292 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 99baf0e099f..658f36ad8b4 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -83,10 +83,6 @@ struct e1000_adapter; #include "e1000_hw.h" -#ifdef CONFIG_E1000_MQ -#include -#include -#endif #ifdef DBG #define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args) @@ -169,12 +165,6 @@ struct e1000_buffer { uint16_t next_to_watch; }; -#ifdef CONFIG_E1000_MQ -struct e1000_queue_stats { - uint64_t packets; - uint64_t bytes; -}; -#endif struct e1000_ps_page { struct page *ps_page[PS_PAGE_BUFFERS]; }; struct e1000_ps_page_dma { uint64_t ps_page_dma[PS_PAGE_BUFFERS]; }; @@ -198,12 +188,7 @@ struct e1000_tx_ring { spinlock_t tx_lock; uint16_t tdh; uint16_t tdt; - boolean_t last_tx_tso; - -#ifdef CONFIG_E1000_MQ - struct e1000_queue_stats tx_stats; -#endif }; struct e1000_rx_ring { @@ -230,9 +215,6 @@ struct e1000_rx_ring { uint16_t rdh; uint16_t rdt; -#ifdef CONFIG_E1000_MQ - struct e1000_queue_stats rx_stats; -#endif }; #define E1000_DESC_UNUSED(R) \ @@ -278,9 +260,6 @@ struct e1000_adapter { /* TX */ struct e1000_tx_ring *tx_ring; /* One per active queue */ -#ifdef CONFIG_E1000_MQ - struct e1000_tx_ring **cpu_tx_ring; /* per-cpu */ -#endif unsigned long tx_queue_len; uint32_t txd_cmd; uint32_t tx_int_delay; @@ -313,11 +292,6 @@ struct e1000_adapter { struct e1000_rx_ring *rx_ring; /* One per active queue */ #ifdef CONFIG_E1000_NAPI struct net_device *polling_netdev; /* One per active queue */ -#endif -#ifdef CONFIG_E1000_MQ - struct net_device **cpu_netdev; /* per-cpu */ - struct call_async_data_struct rx_sched_call_data; - cpumask_t cpumask; #endif int num_tx_queues; int num_rx_queues; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 5cedc81786e..c7b47911f00 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -97,14 +97,7 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "alloc_rx_buff_failed", E1000_STAT(alloc_rx_buff_failed) }, }; -#ifdef CONFIG_E1000_MQ -#define E1000_QUEUE_STATS_LEN \ - (((struct e1000_adapter *)netdev->priv)->num_tx_queues + \ - ((struct e1000_adapter *)netdev->priv)->num_rx_queues) \ - * (sizeof(struct e1000_queue_stats) / sizeof(uint64_t)) -#else #define E1000_QUEUE_STATS_LEN 0 -#endif #define E1000_GLOBAL_STATS_LEN \ sizeof(e1000_gstrings_stats) / sizeof(struct e1000_stats) #define E1000_STATS_LEN (E1000_GLOBAL_STATS_LEN + E1000_QUEUE_STATS_LEN) @@ -1799,11 +1792,6 @@ e1000_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, uint64_t *data) { struct e1000_adapter *adapter = netdev_priv(netdev); -#ifdef CONFIG_E1000_MQ - uint64_t *queue_stat; - int stat_count = sizeof(struct e1000_queue_stats) / sizeof(uint64_t); - int j, k; -#endif int i; e1000_update_stats(adapter); @@ -1812,29 +1800,12 @@ e1000_get_ethtool_stats(struct net_device *netdev, data[i] = (e1000_gstrings_stats[i].sizeof_stat == sizeof(uint64_t)) ? *(uint64_t *)p : *(uint32_t *)p; } -#ifdef CONFIG_E1000_MQ - for (j = 0; j < adapter->num_tx_queues; j++) { - queue_stat = (uint64_t *)&adapter->tx_ring[j].tx_stats; - for (k = 0; k < stat_count; k++) - data[i + k] = queue_stat[k]; - i += k; - } - for (j = 0; j < adapter->num_rx_queues; j++) { - queue_stat = (uint64_t *)&adapter->rx_ring[j].rx_stats; - for (k = 0; k < stat_count; k++) - data[i + k] = queue_stat[k]; - i += k; - } -#endif /* BUG_ON(i != E1000_STATS_LEN); */ } static void e1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) { -#ifdef CONFIG_E1000_MQ - struct e1000_adapter *adapter = netdev_priv(netdev); -#endif uint8_t *p = data; int i; @@ -1849,20 +1820,6 @@ e1000_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data) ETH_GSTRING_LEN); p += ETH_GSTRING_LEN; } -#ifdef CONFIG_E1000_MQ - for (i = 0; i < adapter->num_tx_queues; i++) { - sprintf(p, "tx_queue_%u_packets", i); - p += ETH_GSTRING_LEN; - sprintf(p, "tx_queue_%u_bytes", i); - p += ETH_GSTRING_LEN; - } - for (i = 0; i < adapter->num_rx_queues; i++) { - sprintf(p, "rx_queue_%u_packets", i); - p += ETH_GSTRING_LEN; - sprintf(p, "rx_queue_%u_bytes", i); - p += ETH_GSTRING_LEN; - } -#endif /* BUG_ON(p - data != E1000_STATS_LEN * ETH_GSTRING_LEN); */ break; } diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 5b7d0f425af..af87eb04d83 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -103,7 +103,7 @@ static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver"; #else #define DRIVERNAPI "-NAPI" #endif -#define DRV_VERSION "6.3.9-k4"DRIVERNAPI +#define DRV_VERSION "7.0.33-k2"DRIVERNAPI char e1000_driver_version[] = DRV_VERSION; static char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation."; @@ -191,9 +191,6 @@ static void e1000_exit_module(void); static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent); static void __devexit e1000_remove(struct pci_dev *pdev); static int e1000_alloc_queues(struct e1000_adapter *adapter); -#ifdef CONFIG_E1000_MQ -static void e1000_setup_queue_mapping(struct e1000_adapter *adapter); -#endif static int e1000_sw_init(struct e1000_adapter *adapter); static int e1000_open(struct net_device *netdev); static int e1000_close(struct net_device *netdev); @@ -265,10 +262,6 @@ static int e1000_resume(struct pci_dev *pdev); static void e1000_netpoll (struct net_device *netdev); #endif -#ifdef CONFIG_E1000_MQ -/* for multiple Rx queues */ -void e1000_rx_schedule(void *data); -#endif /* Exported from other modules */ @@ -502,10 +495,6 @@ e1000_up(struct e1000_adapter *adapter) return err; } -#ifdef CONFIG_E1000_MQ - e1000_setup_queue_mapping(adapter); -#endif - adapter->tx_queue_len = netdev->tx_queue_len; mod_timer(&adapter->watchdog_timer, jiffies); @@ -526,9 +515,7 @@ e1000_down(struct e1000_adapter *adapter) e1000_check_mng_mode(&adapter->hw); e1000_irq_disable(adapter); -#ifdef CONFIG_E1000_MQ - while (atomic_read(&adapter->rx_sched_call_data.count) != 0); -#endif + free_irq(adapter->pdev->irq, netdev); #ifdef CONFIG_PCI_MSI if (adapter->hw.mac_type > e1000_82547_rev_2 && @@ -972,10 +959,6 @@ e1000_remove(struct pci_dev *pdev) iounmap(adapter->hw.hw_addr); pci_release_regions(pdev); -#ifdef CONFIG_E1000_MQ - free_percpu(adapter->cpu_netdev); - free_percpu(adapter->cpu_tx_ring); -#endif free_netdev(netdev); pci_disable_device(pdev); @@ -1056,40 +1039,8 @@ e1000_sw_init(struct e1000_adapter *adapter) hw->master_slave = E1000_MASTER_SLAVE; } -#ifdef CONFIG_E1000_MQ - /* Number of supported queues */ - switch (hw->mac_type) { - case e1000_82571: - case e1000_82572: - /* These controllers support 2 tx queues, but with a single - * qdisc implementation, multiple tx queues aren't quite as - * interesting. If we can find a logical way of mapping - * flows to a queue, then perhaps we can up the num_tx_queue - * count back to its default. Until then, we run the risk of - * terrible performance due to SACK overload. */ - adapter->num_tx_queues = 1; - adapter->num_rx_queues = 2; - break; - default: - adapter->num_tx_queues = 1; - adapter->num_rx_queues = 1; - break; - } - adapter->num_rx_queues = min(adapter->num_rx_queues, num_online_cpus()); - adapter->num_tx_queues = min(adapter->num_tx_queues, num_online_cpus()); - DPRINTK(DRV, INFO, "Multiqueue Enabled: Rx Queue count = %u %s\n", - adapter->num_rx_queues, - ((adapter->num_rx_queues == 1) - ? ((num_online_cpus() > 1) - ? "(due to unsupported feature in current adapter)" - : "(due to unsupported system configuration)") - : "")); - DPRINTK(DRV, INFO, "Multiqueue Enabled: Tx Queue count = %u\n", - adapter->num_tx_queues); -#else adapter->num_tx_queues = 1; adapter->num_rx_queues = 1; -#endif if (e1000_alloc_queues(adapter)) { DPRINTK(PROBE, ERR, "Unable to allocate memory for queues\n"); @@ -1152,51 +1103,9 @@ e1000_alloc_queues(struct e1000_adapter *adapter) memset(adapter->polling_netdev, 0, size); #endif -#ifdef CONFIG_E1000_MQ - adapter->rx_sched_call_data.func = e1000_rx_schedule; - adapter->rx_sched_call_data.info = adapter->netdev; - - adapter->cpu_netdev = alloc_percpu(struct net_device *); - adapter->cpu_tx_ring = alloc_percpu(struct e1000_tx_ring *); -#endif - return E1000_SUCCESS; } -#ifdef CONFIG_E1000_MQ -static void __devinit -e1000_setup_queue_mapping(struct e1000_adapter *adapter) -{ - int i, cpu; - - adapter->rx_sched_call_data.func = e1000_rx_schedule; - adapter->rx_sched_call_data.info = adapter->netdev; - cpus_clear(adapter->rx_sched_call_data.cpumask); - - adapter->cpu_netdev = alloc_percpu(struct net_device *); - adapter->cpu_tx_ring = alloc_percpu(struct e1000_tx_ring *); - - lock_cpu_hotplug(); - i = 0; - for_each_online_cpu(cpu) { - *per_cpu_ptr(adapter->cpu_tx_ring, cpu) = &adapter->tx_ring[i % adapter->num_tx_queues]; - /* This is incomplete because we'd like to assign separate - * physical cpus to these netdev polling structures and - * avoid saturating a subset of cpus. - */ - if (i < adapter->num_rx_queues) { - *per_cpu_ptr(adapter->cpu_netdev, cpu) = &adapter->polling_netdev[i]; - adapter->rx_ring[i].cpu = cpu; - cpu_set(cpu, adapter->cpumask); - } else - *per_cpu_ptr(adapter->cpu_netdev, cpu) = NULL; - - i++; - } - unlock_cpu_hotplug(); -} -#endif - /** * e1000_open - Called when a network interface is made active * @netdev: network interface device structure @@ -1435,18 +1344,6 @@ e1000_configure_tx(struct e1000_adapter *adapter) /* Setup the HW Tx Head and Tail descriptor pointers */ switch (adapter->num_tx_queues) { - case 2: - tdba = adapter->tx_ring[1].dma; - tdlen = adapter->tx_ring[1].count * - sizeof(struct e1000_tx_desc); - E1000_WRITE_REG(hw, TDBAL1, (tdba & 0x00000000ffffffffULL)); - E1000_WRITE_REG(hw, TDBAH1, (tdba >> 32)); - E1000_WRITE_REG(hw, TDLEN1, tdlen); - E1000_WRITE_REG(hw, TDH1, 0); - E1000_WRITE_REG(hw, TDT1, 0); - adapter->tx_ring[1].tdh = E1000_TDH1; - adapter->tx_ring[1].tdt = E1000_TDT1; - /* Fall Through */ case 1: default: tdba = adapter->tx_ring[0].dma; @@ -1790,10 +1687,6 @@ e1000_configure_rx(struct e1000_adapter *adapter) uint64_t rdba; struct e1000_hw *hw = &adapter->hw; uint32_t rdlen, rctl, rxcsum, ctrl_ext; -#ifdef CONFIG_E1000_MQ - uint32_t reta, mrqc; - int i; -#endif if (adapter->rx_ps_pages) { rdlen = adapter->rx_ring[0].count * @@ -1837,18 +1730,6 @@ e1000_configure_rx(struct e1000_adapter *adapter) /* Setup the HW Rx Head and Tail Descriptor Pointers and * the Base and Length of the Rx Descriptor Ring */ switch (adapter->num_rx_queues) { -#ifdef CONFIG_E1000_MQ - case 2: - rdba = adapter->rx_ring[1].dma; - E1000_WRITE_REG(hw, RDBAL1, (rdba & 0x00000000ffffffffULL)); - E1000_WRITE_REG(hw, RDBAH1, (rdba >> 32)); - E1000_WRITE_REG(hw, RDLEN1, rdlen); - E1000_WRITE_REG(hw, RDH1, 0); - E1000_WRITE_REG(hw, RDT1, 0); - adapter->rx_ring[1].rdh = E1000_RDH1; - adapter->rx_ring[1].rdt = E1000_RDT1; - /* Fall Through */ -#endif case 1: default: rdba = adapter->rx_ring[0].dma; @@ -1862,46 +1743,6 @@ e1000_configure_rx(struct e1000_adapter *adapter) break; } -#ifdef CONFIG_E1000_MQ - if (adapter->num_rx_queues > 1) { - uint32_t random[10]; - - get_random_bytes(&random[0], 40); - - if (hw->mac_type <= e1000_82572) { - E1000_WRITE_REG(hw, RSSIR, 0); - E1000_WRITE_REG(hw, RSSIM, 0); - } - - switch (adapter->num_rx_queues) { - case 2: - default: - reta = 0x00800080; - mrqc = E1000_MRQC_ENABLE_RSS_2Q; - break; - } - - /* Fill out redirection table */ - for (i = 0; i < 32; i++) - E1000_WRITE_REG_ARRAY(hw, RETA, i, reta); - /* Fill out hash function seeds */ - for (i = 0; i < 10; i++) - E1000_WRITE_REG_ARRAY(hw, RSSRK, i, random[i]); - - mrqc |= (E1000_MRQC_RSS_FIELD_IPV4 | - E1000_MRQC_RSS_FIELD_IPV4_TCP); - E1000_WRITE_REG(hw, MRQC, mrqc); - } - - /* Multiqueue and packet checksumming are mutually exclusive. */ - if (hw->mac_type >= e1000_82571) { - rxcsum = E1000_READ_REG(hw, RXCSUM); - rxcsum |= E1000_RXCSUM_PCSD; - E1000_WRITE_REG(hw, RXCSUM, rxcsum); - } - -#else - /* Enable 82543 Receive Checksum Offload for TCP and UDP */ if (hw->mac_type >= e1000_82543) { rxcsum = E1000_READ_REG(hw, RXCSUM); @@ -1920,7 +1761,6 @@ e1000_configure_rx(struct e1000_adapter *adapter) } E1000_WRITE_REG(hw, RXCSUM, rxcsum); } -#endif /* CONFIG_E1000_MQ */ if (hw->mac_type == e1000_82573) E1000_WRITE_REG(hw, ERT, 0x0100); @@ -2465,9 +2305,6 @@ e1000_watchdog_task(struct e1000_adapter *adapter) e1000_update_adaptive(&adapter->hw); -#ifdef CONFIG_E1000_MQ - txdr = *per_cpu_ptr(adapter->cpu_tx_ring, smp_processor_id()); -#endif if (!netif_carrier_ok(netdev)) { if (E1000_DESC_UNUSED(txdr) + 1 < txdr->count) { /* We've lost link, so the controller stops DMA, @@ -2881,11 +2718,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) unsigned int f; len -= skb->data_len; -#ifdef CONFIG_E1000_MQ - tx_ring = *per_cpu_ptr(adapter->cpu_tx_ring, smp_processor_id()); -#else tx_ring = adapter->tx_ring; -#endif if (unlikely(skb->len <= 0)) { dev_kfree_skb_any(skb); @@ -3288,29 +3121,6 @@ e1000_update_stats(struct e1000_adapter *adapter) spin_unlock_irqrestore(&adapter->stats_lock, flags); } -#ifdef CONFIG_E1000_MQ -void -e1000_rx_schedule(void *data) -{ - struct net_device *poll_dev, *netdev = data; - struct e1000_adapter *adapter = netdev->priv; - int this_cpu = get_cpu(); - - poll_dev = *per_cpu_ptr(adapter->cpu_netdev, this_cpu); - if (poll_dev == NULL) { - put_cpu(); - return; - } - - if (likely(netif_rx_schedule_prep(poll_dev))) - __netif_rx_schedule(poll_dev); - else - e1000_irq_enable(adapter); - - put_cpu(); -} -#endif - /** * e1000_intr - Interrupt Handler * @irq: interrupt number @@ -3355,26 +3165,11 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) E1000_WRITE_REG(hw, IMC, ~0); E1000_WRITE_FLUSH(hw); } -#ifdef CONFIG_E1000_MQ - if (atomic_read(&adapter->rx_sched_call_data.count) == 0) { - /* We must setup the cpumask once count == 0 since - * each cpu bit is cleared when the work is done. */ - adapter->rx_sched_call_data.cpumask = adapter->cpumask; - atomic_add(adapter->num_rx_queues - 1, &adapter->irq_sem); - atomic_set(&adapter->rx_sched_call_data.count, - adapter->num_rx_queues); - smp_call_async_mask(&adapter->rx_sched_call_data); - } else { - printk("call_data.count == %u\n", atomic_read(&adapter->rx_sched_call_data.count)); - } -#else /* if !CONFIG_E1000_MQ */ if (likely(netif_rx_schedule_prep(&adapter->polling_netdev[0]))) __netif_rx_schedule(&adapter->polling_netdev[0]); else e1000_irq_enable(adapter); -#endif /* CONFIG_E1000_MQ */ - -#else /* if !CONFIG_E1000_NAPI */ +#else /* Writing IMC and IMS is needed for 82547. * Due to Hub Link bus being occupied, an interrupt * de-assertion message is not able to be sent. @@ -3398,7 +3193,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) if (hw->mac_type == e1000_82547 || hw->mac_type == e1000_82547_rev_2) e1000_irq_enable(adapter); -#endif /* CONFIG_E1000_NAPI */ +#endif return IRQ_HANDLED; } @@ -3486,18 +3281,12 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, buffer_info = &tx_ring->buffer_info[i]; cleaned = (i == eop); -#ifdef CONFIG_E1000_MQ - tx_ring->tx_stats.bytes += buffer_info->length; -#endif e1000_unmap_and_free_tx_resource(adapter, buffer_info); memset(tx_desc, 0, sizeof(struct e1000_tx_desc)); if (unlikely(++i == tx_ring->count)) i = 0; } -#ifdef CONFIG_E1000_MQ - tx_ring->tx_stats.packets++; -#endif eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); @@ -3733,10 +3522,6 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; -#ifdef CONFIG_E1000_MQ - rx_ring->rx_stats.packets++; - rx_ring->rx_stats.bytes += length; -#endif next_desc: rx_desc->status = 0; @@ -3878,10 +3663,6 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, } #endif /* CONFIG_E1000_NAPI */ netdev->last_rx = jiffies; -#ifdef CONFIG_E1000_MQ - rx_ring->rx_stats.packets++; - rx_ring->rx_stats.bytes += length; -#endif next_desc: rx_desc->wb.middle.status_error &= ~0xFF; -- cgit v1.2.3 From 9f644d518f35903ecaff062d6e9e4f7080d80cfb Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:16:59 -0800 Subject: e1000: Fix dead counters Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_ethtool.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index c7b47911f00..9c77413faf0 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -60,7 +60,6 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "tx_bytes", E1000_STAT(net_stats.tx_bytes) }, { "rx_errors", E1000_STAT(net_stats.rx_errors) }, { "tx_errors", E1000_STAT(net_stats.tx_errors) }, - { "rx_dropped", E1000_STAT(net_stats.rx_dropped) }, { "tx_dropped", E1000_STAT(net_stats.tx_dropped) }, { "multicast", E1000_STAT(net_stats.multicast) }, { "collisions", E1000_STAT(net_stats.collisions) }, -- cgit v1.2.3 From 0989aa431636ffb347314f0e2f367fdd16d7a57f Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:17:16 -0800 Subject: e1000: Fix lock up while setting ring parameters Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_ethtool.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 9c77413faf0..f7e81e96a19 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -634,6 +634,9 @@ e1000_set_ringparam(struct net_device *netdev, struct e1000_rx_ring *rxdr, *rx_old, *rx_new; int i, err, tx_ring_size, rx_ring_size; + if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) + return -EINVAL; + tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues; rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues; @@ -661,9 +664,6 @@ e1000_set_ringparam(struct net_device *netdev, txdr = adapter->tx_ring; rxdr = adapter->rx_ring; - if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) - return -EINVAL; - rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD); rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD)); -- cgit v1.2.3 From 5b66ba0db8d04d99926445bc7d9f920bb5d744ed Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:17:30 -0800 Subject: e1000: Fix unecessary delay for 82573 controllers Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_hw.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index beeec0fbbea..0af68bab974 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -6746,12 +6746,6 @@ e1000_get_phy_cfg_done(struct e1000_hw *hw) break; } - /* PHY configuration from NVM just starts after EECD_AUTO_RD sets to high. - * Need to wait for PHY configuration completion before accessing NVM - * and PHY. */ - if (hw->mac_type == e1000_82573) - msec_delay(25); - return E1000_SUCCESS; } -- cgit v1.2.3 From c5f226fe97e8025440aa330aa2c8e1c66bfdc96b Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:17:55 -0800 Subject: e1000: Fix AMT losing connectivity when switching VLAN in passive mode Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index af87eb04d83..0109cc72746 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -373,7 +373,8 @@ e1000_update_mng_vlan(struct e1000_adapter *adapter) (vid != old_vid) && !adapter->vlgrp->vlan_devices[old_vid]) e1000_vlan_rx_kill_vid(netdev, old_vid); - } + } else + adapter->mng_vlan_id = vid; } } -- cgit v1.2.3 From 20a44028f06030a71a1250ad8efb0a7fb556c3ea Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:18:08 -0800 Subject: e1000: Fix dhcp issue when the skb structure fields are not filled properly Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 0109cc72746..a525c95266f 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2678,7 +2678,7 @@ e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct sk_buff *skb) E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) ) return 0; } - if ((skb->len > MINIMUM_DHCP_PACKET_SIZE) && (!skb->protocol)) { + if (skb->len > MINIMUM_DHCP_PACKET_SIZE) { struct ethhdr *eth = (struct ethhdr *) skb->data; if ((htons(ETH_P_IP) == eth->h_proto)) { const struct iphdr *ip = -- cgit v1.2.3 From 497fce5e72a21f45929a786bf416ac03cbe09e2f Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:18:20 -0800 Subject: e1000: Fix 82543 issue when reading eeprom Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_hw.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 0af68bab974..1b8869e3953 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -906,7 +906,13 @@ e1000_setup_link(struct e1000_hw *hw) * signal detection. So this should be done before e1000_setup_pcs_link() * or e1000_phy_setup() is called. */ - if(hw->mac_type == e1000_82543) { + if (hw->mac_type == e1000_82543) { + ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, + 1, &eeprom_data); + if (ret_val) { + DEBUGOUT("EEPROM Read Error\n"); + return -E1000_ERR_EEPROM; + } ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) << SWDPIO__EXT_SHIFT); E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext); -- cgit v1.2.3 From 8df06e504e999ff729f1b2a2e573d96bf3690dbc Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:18:32 -0800 Subject: e1000: Fix RSS if enabled in mid-connection Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_hw.c | 30 +++++++++++++++++++++++++++++- drivers/net/e1000/e1000_hw.h | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 1b8869e3953..5ee42c75adb 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -4755,8 +4755,36 @@ e1000_rar_set(struct e1000_hw *hw, rar_low = ((uint32_t) addr[0] | ((uint32_t) addr[1] << 8) | ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24)); + rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8)); - rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV); + /* Disable Rx and flush all Rx frames before enabling RSS to avoid Rx + * unit hang. + * + * Description: + * If there are any Rx frames queued up or otherwise present in the HW + * before RSS is enabled, and then we enable RSS, the HW Rx unit will + * hang. To work around this issue, we have to disable receives and + * flush out all Rx frames before we enable RSS. To do so, we modify we + * redirect all Rx traffic to manageability and then reset the HW. + * This flushes away Rx frames, and (since the redirections to + * manageability persists across resets) keeps new ones from coming in + * while we work. Then, we clear the Address Valid AV bit for all MAC + * addresses and undo the re-direction to manageability. + * Now, frames are coming in again, but the MAC won't accept them, so + * far so good. We now proceed to initialize RSS (if necessary) and + * configure the Rx unit. Last, we re-enable the AV bits and continue + * on our merry way. + */ + switch (hw->mac_type) { + case e1000_82571: + case e1000_82572: + if (hw->leave_av_bit_off == TRUE) + break; + default: + /* Indicate to hardware the Address is Valid. */ + rar_high |= E1000_RAH_AV; + break; + } E1000_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low); E1000_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high); diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index f1219dd9dba..0848e556b1a 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -1361,6 +1361,7 @@ struct e1000_hw { boolean_t ifs_params_forced; boolean_t in_ifs_mode; boolean_t mng_reg_access_disabled; + boolean_t leave_av_bit_off; }; -- cgit v1.2.3 From 8491682986e04fe7b258e5ba1d22f9a0ea2d803e Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:18:48 -0800 Subject: e1000: Fix Quadport Wake on LAN Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000.h | 1 + drivers/net/e1000/e1000_ethtool.c | 31 ++++++++++++++++++++++++++++++- drivers/net/e1000/e1000_main.c | 10 ++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 658f36ad8b4..a18782748d5 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -242,6 +242,7 @@ struct e1000_adapter { uint32_t rx_buffer_len; uint32_t part_num; uint32_t wol; + uint32_t ksp3_port_a; uint32_t smartspeed; uint32_t en_mng_pt; uint16_t link_speed; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index f7e81e96a19..f1b9cf4643c 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -1632,10 +1632,26 @@ e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) case E1000_DEV_ID_82546EB_QUAD_COPPER: case E1000_DEV_ID_82545EM_FIBER: case E1000_DEV_ID_82545EM_COPPER: + case E1000_DEV_ID_82546GB_QUAD_COPPER: wol->supported = 0; wol->wolopts = 0; return; + case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: + /* device id 10B5 port-A supports wol */ + if (!adapter->ksp3_port_a) { + wol->supported = 0; + return; + } + /* KSP3 does not suppport UCAST wake-ups for any interface */ + wol->supported = WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC; + + if (adapter->wol & E1000_WUFC_EX) + DPRINTK(DRV, ERR, "Interface does not support " + "directed (unicast) frame wake-up packets\n"); + wol->wolopts = 0; + goto do_defaults; + case E1000_DEV_ID_82546EB_FIBER: case E1000_DEV_ID_82546GB_FIBER: case E1000_DEV_ID_82571EB_FIBER: @@ -1650,8 +1666,9 @@ e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) default: wol->supported = WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_MAGIC; - wol->wolopts = 0; + +do_defaults: if (adapter->wol & E1000_WUFC_EX) wol->wolopts |= WAKE_UCAST; if (adapter->wol & E1000_WUFC_MC) @@ -1676,10 +1693,22 @@ e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) case E1000_DEV_ID_82543GC_COPPER: case E1000_DEV_ID_82544EI_FIBER: case E1000_DEV_ID_82546EB_QUAD_COPPER: + case E1000_DEV_ID_82546GB_QUAD_COPPER: case E1000_DEV_ID_82545EM_FIBER: case E1000_DEV_ID_82545EM_COPPER: return wol->wolopts ? -EOPNOTSUPP : 0; + case E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3: + /* device id 10B5 port-A supports wol */ + if (!adapter->ksp3_port_a) + return wol->wolopts ? -EOPNOTSUPP : 0; + + if (wol->wolopts & WAKE_UCAST) { + DPRINTK(DRV, ERR, "Interface does not support " + "directed (unicast) frame wake-up packets\n"); + return -EOPNOTSUPP; + } + case E1000_DEV_ID_82546EB_FIBER: case E1000_DEV_ID_82546GB_FIBER: case E1000_DEV_ID_82571EB_FIBER: diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index a525c95266f..aad5373a8ae 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -651,6 +651,7 @@ e1000_probe(struct pci_dev *pdev, unsigned long mmio_start, mmio_len; static int cards_found = 0; + static int e1000_ksp3_port_a = 0; /* global ksp3 port a indication */ int i, err, pci_using_dac; uint16_t eeprom_data; uint16_t eeprom_apme_mask = E1000_EEPROM_APME; @@ -743,6 +744,15 @@ e1000_probe(struct pci_dev *pdev, if ((err = e1000_check_phy_reset_block(&adapter->hw))) DPRINTK(PROBE, INFO, "PHY reset is blocked due to SOL/IDER session.\n"); + /* if ksp3, indicate if it's port a being setup */ + if (pdev->device == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 && + e1000_ksp3_port_a == 0) + adapter->ksp3_port_a = 1; + e1000_ksp3_port_a++; + /* Reset for multiple KP3 adapters */ + if (e1000_ksp3_port_a == 4) + e1000_ksp3_port_a = 0; + if (adapter->hw.mac_type >= e1000_82543) { netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | -- cgit v1.2.3 From 7e6c9861bbc2fcd2438da910c006781784968a7c Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:19:30 -0800 Subject: e1000: Fix network problems when forced at 100Mb/s and to fix TSO when forced at 100Mb/s Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000.h | 5 +++ drivers/net/e1000/e1000_ethtool.c | 3 ++ drivers/net/e1000/e1000_main.c | 67 +++++++++++++++++++++++++++++++++------ drivers/net/e1000/e1000_param.c | 2 +- 4 files changed, 66 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index a18782748d5..3319c19cbee 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -332,6 +332,11 @@ struct e1000_adapter { int msg_enable; #ifdef CONFIG_PCI_MSI boolean_t have_msi; +#endif + /* to not mess up cache alignment, always add to the bottom */ + boolean_t txb2b; +#ifdef NETIF_F_TSO + boolean_t tso_force; #endif }; #endif /* _E1000_H_ */ diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index f1b9cf4643c..70238e089f1 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -338,6 +338,9 @@ e1000_set_tso(struct net_device *netdev, uint32_t data) netdev->features |= NETIF_F_TSO; else netdev->features &= ~NETIF_F_TSO; + + DPRINTK(PROBE, INFO, "TSO is %s\n", data ? "Enabled" : "Disabled"); + adapter->tso_force = TRUE; return 0; } #endif /* NETIF_F_TSO */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index aad5373a8ae..6ee8ed5606f 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -1405,10 +1405,13 @@ e1000_configure_tx(struct e1000_adapter *adapter) tctl = E1000_READ_REG(hw, TCTL); tctl &= ~E1000_TCTL_CT; - tctl |= E1000_TCTL_EN | E1000_TCTL_PSP | E1000_TCTL_RTLC | + tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT); - E1000_WRITE_REG(hw, TCTL, tctl); +#ifdef DISABLE_MULR + /* disable Multiple Reads for debugging */ + tctl &= ~E1000_TCTL_MULR; +#endif if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) { tarc = E1000_READ_REG(hw, TARC0); @@ -1439,6 +1442,9 @@ e1000_configure_tx(struct e1000_adapter *adapter) if (hw->mac_type == e1000_82544 && hw->bus_type == e1000_bus_type_pcix) adapter->pcix_82544 = 1; + + E1000_WRITE_REG(hw, TCTL, tctl); + } /** @@ -2243,7 +2249,7 @@ e1000_watchdog_task(struct e1000_adapter *adapter) { struct net_device *netdev = adapter->netdev; struct e1000_tx_ring *txdr = adapter->tx_ring; - uint32_t link; + uint32_t link, tctl; e1000_check_for_link(&adapter->hw); if (adapter->hw.mac_type == e1000_82573) { @@ -2269,20 +2275,61 @@ e1000_watchdog_task(struct e1000_adapter *adapter) adapter->link_duplex == FULL_DUPLEX ? "Full Duplex" : "Half Duplex"); - /* tweak tx_queue_len according to speed/duplex */ + /* tweak tx_queue_len according to speed/duplex + * and adjust the timeout factor */ netdev->tx_queue_len = adapter->tx_queue_len; adapter->tx_timeout_factor = 1; - if (adapter->link_duplex == HALF_DUPLEX) { + adapter->txb2b = 1; + switch (adapter->link_speed) { + case SPEED_10: + adapter->txb2b = 0; + netdev->tx_queue_len = 10; + adapter->tx_timeout_factor = 8; + break; + case SPEED_100: + adapter->txb2b = 0; + netdev->tx_queue_len = 100; + /* maybe add some timeout factor ? */ + break; + } + + if ((adapter->hw.mac_type == e1000_82571 || + adapter->hw.mac_type == e1000_82572) && + adapter->txb2b == 0) { +#define SPEED_MODE_BIT (1 << 21) + uint32_t tarc0; + tarc0 = E1000_READ_REG(&adapter->hw, TARC0); + tarc0 &= ~SPEED_MODE_BIT; + E1000_WRITE_REG(&adapter->hw, TARC0, tarc0); + } + +#ifdef NETIF_F_TSO + /* disable TSO for pcie and 10/100 speeds, to avoid + * some hardware issues */ + if (!adapter->tso_force && + adapter->hw.bus_type == e1000_bus_type_pci_express){ switch (adapter->link_speed) { case SPEED_10: - netdev->tx_queue_len = 10; - adapter->tx_timeout_factor = 8; - break; case SPEED_100: - netdev->tx_queue_len = 100; + DPRINTK(PROBE,INFO, + "10/100 speed: disabling TSO\n"); + netdev->features &= ~NETIF_F_TSO; + break; + case SPEED_1000: + netdev->features |= NETIF_F_TSO; + break; + default: + /* oops */ break; } } +#endif + + /* enable transmits in the hardware, need to do this + * after setting TARC0 */ + tctl = E1000_READ_REG(&adapter->hw, TCTL); + tctl |= E1000_TCTL_EN; + E1000_WRITE_REG(&adapter->hw, TCTL, tctl); netif_carrier_on(netdev); netif_wake_queue(netdev); @@ -3319,7 +3366,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, adapter->detect_tx_hung = FALSE; if (tx_ring->buffer_info[eop].dma && time_after(jiffies, tx_ring->buffer_info[eop].time_stamp + - adapter->tx_timeout_factor * HZ) + (adapter->tx_timeout_factor * HZ)) && !(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF)) { diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index 3768d83cd57..e0a4d37d1b8 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c @@ -268,7 +268,7 @@ e1000_validate_option(int *value, struct e1000_option *opt, BUG(); } - DPRINTK(PROBE, INFO, "Invalid %s specified (%i) %s\n", + DPRINTK(PROBE, INFO, "Invalid %s value specified (%i) %s\n", opt->name, *value, opt->err); *value = opt->def; return -1; -- cgit v1.2.3 From 329bfd0b6d5ffec00b787f1d0e68eef63d8b1d56 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:20:02 -0800 Subject: e1000: Fix filling skb descriptors while using packet split - Simplified by calling skb_fill_page_desc(), which is more efficient. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_main.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 6ee8ed5606f..9e58419c872 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3686,12 +3686,9 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, pci_unmap_page(pdev, ps_page_dma->ps_page_dma[j], PAGE_SIZE, PCI_DMA_FROMDEVICE); ps_page_dma->ps_page_dma[j] = 0; - skb_shinfo(skb)->frags[j].page = - ps_page->ps_page[j]; + skb_fill_page_desc(skb, j, ps_page->ps_page[j], 0, + length); ps_page->ps_page[j] = NULL; - skb_shinfo(skb)->frags[j].page_offset = 0; - skb_shinfo(skb)->frags[j].size = length; - skb_shinfo(skb)->nr_frags++; skb->len += length; skb->data_len += length; } -- cgit v1.2.3 From 9f68788856b134f93d9d10b19aa902924c61fc02 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:20:17 -0800 Subject: e1000: Add 82573 controller support to TSO fix Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_main.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 9e58419c872..6603bd13906 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2796,21 +2796,29 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) max_per_txd = min(mss << 2, max_per_txd); max_txd_pwr = fls(max_per_txd) - 1; - /* TSO Workaround for 82571/2 Controllers -- if skb->data + /* TSO Workaround for 82571/2/3 Controllers -- if skb->data * points to just header, pull a few bytes of payload from * frags into skb->data */ hdr_len = ((skb->h.raw - skb->data) + (skb->h.th->doff << 2)); - if (skb->data_len && (hdr_len == (skb->len - skb->data_len)) && - (adapter->hw.mac_type == e1000_82571 || - adapter->hw.mac_type == e1000_82572)) { - unsigned int pull_size; - pull_size = min((unsigned int)4, skb->data_len); - if (!__pskb_pull_tail(skb, pull_size)) { - printk(KERN_ERR "__pskb_pull_tail failed.\n"); - dev_kfree_skb_any(skb); - return -EFAULT; + if (skb->data_len && (hdr_len == (skb->len - skb->data_len))) { + switch (adapter->hw.mac_type) { + unsigned int pull_size; + case e1000_82571: + case e1000_82572: + case e1000_82573: + pull_size = min((unsigned int)4, skb->data_len); + if (!__pskb_pull_tail(skb, pull_size)) { + printk(KERN_ERR + "__pskb_pull_tail failed.\n"); + dev_kfree_skb_any(skb); + return -EFAULT; + } + len = skb->len - skb->data_len; + break; + default: + /* do nothing */ + break; } - len = skb->len - skb->data_len; } } -- cgit v1.2.3 From 85b22eb632dc75887ba99edad49307a02c2ae7ec Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:20:29 -0800 Subject: e1000: Add enabled Jumbo frame support for 82573L Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_hw.h | 5 +++++ drivers/net/e1000/e1000_main.c | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 0848e556b1a..f565b201c49 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -1875,6 +1875,7 @@ struct e1000_hw { #define E1000_MANC_TCO_RESET 0x00010000 /* TCO Reset Occurred */ #define E1000_MANC_RCV_TCO_EN 0x00020000 /* Receive TCO Packets Enabled */ #define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */ +#define E1000_MANC_RCV_ALL 0x00080000 /* Receive All Enabled */ #define E1000_MANC_BLK_PHY_RST_ON_IDE 0x00040000 /* Block phy resets */ #define E1000_MANC_EN_MAC_ADDR_FILTER 0x00100000 /* Enable MAC address * filtering */ @@ -2036,6 +2037,7 @@ struct e1000_host_command_info { #define EEPROM_INIT_CONTROL1_REG 0x000A #define EEPROM_INIT_CONTROL2_REG 0x000F #define EEPROM_INIT_CONTROL3_PORT_B 0x0014 +#define EEPROM_INIT_3GIO_3 0x001A #define EEPROM_INIT_CONTROL3_PORT_A 0x0024 #define EEPROM_CFG 0x0012 #define EEPROM_FLASH_VERSION 0x0032 @@ -2085,6 +2087,9 @@ struct e1000_host_command_info { #define EEPROM_WORD0F_ANE 0x0800 #define EEPROM_WORD0F_SWPDIO_EXT 0x00F0 +/* Mask bits for fields in Word 0x1a of the EEPROM */ +#define EEPROM_WORD1A_ASPM_MASK 0x000C + /* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */ #define EEPROM_SUM 0xBABA diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 6603bd13906..58561a4955e 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2978,6 +2978,7 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) { struct e1000_adapter *adapter = netdev_priv(netdev); int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE; + uint16_t eeprom_data = 0; if ((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) || (max_frame > MAX_JUMBO_FRAME_SIZE)) { @@ -2989,12 +2990,25 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) switch (adapter->hw.mac_type) { case e1000_82542_rev2_0: case e1000_82542_rev2_1: - case e1000_82573: if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { DPRINTK(PROBE, ERR, "Jumbo Frames not supported.\n"); return -EINVAL; } break; + case e1000_82573: + /* only enable jumbo frames if ASPM is disabled completely + * this means both bits must be zero in 0x1A bits 3:2 */ + e1000_read_eeprom(&adapter->hw, EEPROM_INIT_3GIO_3, 1, + &eeprom_data); + if (eeprom_data & EEPROM_WORD1A_ASPM_MASK) { + if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) { + DPRINTK(PROBE, ERR, + "Jumbo Frames not supported.\n"); + return -EINVAL; + } + break; + } + /* fall through to get support */ case e1000_82571: case e1000_82572: #define MAX_STD_JUMBO_FRAME_SIZE 9234 -- cgit v1.2.3 From 2a1af5d7dfd809b16fb69f3f0fc073d9b6b7c6ac Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:20:43 -0800 Subject: e1000: Add performance enahancement by balancing TX and RX Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 58561a4955e..e80378a220d 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3349,6 +3349,9 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, struct e1000_tx_desc *tx_desc, *eop_desc; struct e1000_buffer *buffer_info; unsigned int i, eop; +#ifdef CONFIG_E1000_NAPI + unsigned int count = 0; +#endif boolean_t cleaned = FALSE; i = tx_ring->next_to_clean; @@ -3370,6 +3373,11 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter, eop = tx_ring->buffer_info[i].next_to_watch; eop_desc = E1000_TX_DESC(*tx_ring, eop); +#ifdef CONFIG_E1000_NAPI +#define E1000_TX_WEIGHT 64 + /* weight of a sort for tx, to avoid endless transmit cleanup */ + if (count++ == E1000_TX_WEIGHT) break; +#endif } tx_ring->next_to_clean = i; -- cgit v1.2.3 From 6418ecc68e1d9416451b6f78ebb2c0b077e0abf2 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:21:10 -0800 Subject: e1000: Add support for new hardware (ESB2) Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_ethtool.c | 3 + drivers/net/e1000/e1000_hw.c | 685 +++++++++++++++++++++++++++++++++++++- drivers/net/e1000/e1000_hw.h | 287 ++++++++++++++++ drivers/net/e1000/e1000_main.c | 5 + 4 files changed, 964 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 70238e089f1..0d6a16c5f8c 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -589,6 +589,7 @@ e1000_get_drvinfo(struct net_device *netdev, case e1000_82571: case e1000_82572: case e1000_82573: + case e1000_80003es2lan: sprintf(firmware_version, "%d.%d-%d", (eeprom_data & 0xF000) >> 12, (eeprom_data & 0x0FF0) >> 4, @@ -762,6 +763,7 @@ e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data) /* there are several bits on newer hardware that are r/w */ case e1000_82571: case e1000_82572: + case e1000_80003es2lan: toggle = 0x7FFFF3FF; break; case e1000_82573: @@ -1320,6 +1322,7 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter) case e1000_82571: case e1000_82572: case e1000_82573: + case e1000_80003es2lan: return e1000_integrated_phy_loopback(adapter); break; diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 5ee42c75adb..63e237084a5 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -100,6 +100,8 @@ static void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, #define E1000_WRITE_REG_IO(a, reg, val) \ e1000_write_reg_io((a), E1000_##reg, val) +static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw); +static int32_t e1000_configure_kmrn_for_1000(struct e1000_hw *hw); /* IGP cable length table */ static const @@ -153,6 +155,11 @@ e1000_set_phy_type(struct e1000_hw *hw) hw->phy_type = e1000_phy_igp; break; } + case GG82563_E_PHY_ID: + if (hw->mac_type == e1000_80003es2lan) { + hw->phy_type = e1000_phy_gg82563; + break; + } /* Fall Through */ default: /* Should never have loaded on this device */ @@ -353,12 +360,19 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82573L: hw->mac_type = e1000_82573; break; + case E1000_DEV_ID_80003ES2LAN_COPPER_DPT: + case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: + hw->mac_type = e1000_80003es2lan; + break; default: /* Should never have loaded on this device */ return -E1000_ERR_MAC_TYPE; } switch(hw->mac_type) { + case e1000_80003es2lan: + hw->swfw_sync_present = TRUE; + /* fall through */ case e1000_82571: case e1000_82572: case e1000_82573: @@ -399,6 +413,7 @@ e1000_set_media_type(struct e1000_hw *hw) case E1000_DEV_ID_82546GB_SERDES: case E1000_DEV_ID_82571EB_SERDES: case E1000_DEV_ID_82572EI_SERDES: + case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: hw->media_type = e1000_media_type_internal_serdes; break; default: @@ -575,6 +590,7 @@ e1000_reset_hw(struct e1000_hw *hw) /* fall through */ case e1000_82571: case e1000_82572: + case e1000_80003es2lan: ret_val = e1000_get_auto_rd_done(hw); if(ret_val) /* We don't want to continue accessing MAC registers. */ @@ -641,6 +657,7 @@ e1000_init_hw(struct e1000_hw *hw) uint16_t cmd_mmrbc; uint16_t stat_mmrbc; uint32_t mta_size; + uint32_t reg_data; uint32_t ctrl_ext; DEBUGFUNC("e1000_init_hw"); @@ -739,6 +756,7 @@ e1000_init_hw(struct e1000_hw *hw) case e1000_82571: case e1000_82572: case e1000_82573: + case e1000_80003es2lan: ctrl |= E1000_TXDCTL_COUNT_DESC; break; } @@ -752,12 +770,34 @@ e1000_init_hw(struct e1000_hw *hw) switch (hw->mac_type) { default: break; + case e1000_80003es2lan: + /* Enable retransmit on late collisions */ + reg_data = E1000_READ_REG(hw, TCTL); + reg_data |= E1000_TCTL_RTLC; + E1000_WRITE_REG(hw, TCTL, reg_data); + + /* Configure Gigabit Carry Extend Padding */ + reg_data = E1000_READ_REG(hw, TCTL_EXT); + reg_data &= ~E1000_TCTL_EXT_GCEX_MASK; + reg_data |= DEFAULT_80003ES2LAN_TCTL_EXT_GCEX; + E1000_WRITE_REG(hw, TCTL_EXT, reg_data); + + /* Configure Transmit Inter-Packet Gap */ + reg_data = E1000_READ_REG(hw, TIPG); + reg_data &= ~E1000_TIPG_IPGT_MASK; + reg_data |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000; + E1000_WRITE_REG(hw, TIPG, reg_data); + + reg_data = E1000_READ_REG_ARRAY(hw, FFLT, 0x0001); + reg_data &= ~0x00100000; + E1000_WRITE_REG_ARRAY(hw, FFLT, 0x0001, reg_data); + /* Fall through */ case e1000_82571: case e1000_82572: ctrl = E1000_READ_REG(hw, TXDCTL1); - ctrl &= ~E1000_TXDCTL_WTHRESH; - ctrl |= E1000_TXDCTL_COUNT_DESC | E1000_TXDCTL_FULL_TX_DESC_WB; - ctrl |= (1 << 22); + ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB; + if(hw->mac_type >= e1000_82571) + ctrl |= E1000_TXDCTL_COUNT_DESC; E1000_WRITE_REG(hw, TXDCTL1, ctrl); break; } @@ -1314,6 +1354,154 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw) return E1000_SUCCESS; } +/******************************************************************** +* Copper link setup for e1000_phy_gg82563 series. +* +* hw - Struct containing variables accessed by shared code +*********************************************************************/ +static int32_t +e1000_copper_link_ggp_setup(struct e1000_hw *hw) +{ + int32_t ret_val; + uint16_t phy_data; + uint32_t reg_data; + + DEBUGFUNC("e1000_copper_link_ggp_setup"); + + if(!hw->phy_reset_disable) { + + /* Enable CRS on TX for half-duplex operation. */ + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, + &phy_data); + if(ret_val) + return ret_val; + + phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; + /* Use 25MHz for both link down and 1000BASE-T for Tx clock */ + phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ; + + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, + phy_data); + if(ret_val) + return ret_val; + + /* Options: + * MDI/MDI-X = 0 (default) + * 0 - Auto for all speeds + * 1 - MDI mode + * 2 - MDI-X mode + * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes) + */ + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_SPEC_CTRL, &phy_data); + if(ret_val) + return ret_val; + + phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK; + + switch (hw->mdix) { + case 1: + phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI; + break; + case 2: + phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDIX; + break; + case 0: + default: + phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO; + break; + } + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + if(hw->disable_polarity_correction == 1) + phy_data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_SPEC_CTRL, phy_data); + + if(ret_val) + return ret_val; + + /* SW Reset the PHY so all changes take effect */ + ret_val = e1000_phy_reset(hw); + if (ret_val) { + DEBUGOUT("Error Resetting the PHY\n"); + return ret_val; + } + } /* phy_reset_disable */ + + if (hw->mac_type == e1000_80003es2lan) { + /* Bypass RX and TX FIFO's */ + ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_FIFO_CTRL, + E1000_KUMCTRLSTA_FIFO_CTRL_RX_BYPASS | + E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS); + if (ret_val) + return ret_val; + + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_SPEC_CTRL_2, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG; + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_SPEC_CTRL_2, phy_data); + + if (ret_val) + return ret_val; + + reg_data = E1000_READ_REG(hw, CTRL_EXT); + reg_data &= ~(E1000_CTRL_EXT_LINK_MODE_MASK); + E1000_WRITE_REG(hw, CTRL_EXT, reg_data); + + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_PWR_MGMT_CTRL, + &phy_data); + if (ret_val) + return ret_val; + + /* Do not init these registers when the HW is in IAMT mode, since the + * firmware will have already initialized them. We only initialize + * them if the HW is not in IAMT mode. + */ + if (e1000_check_mng_mode(hw) == FALSE) { + /* Enable Electrical Idle on the PHY */ + phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE; + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_PWR_MGMT_CTRL, + phy_data); + if (ret_val) + return ret_val; + + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, + &phy_data); + if (ret_val) + return ret_val; + + /* Enable Pass False Carrier on the PHY */ + phy_data |= GG82563_KMCR_PASS_FALSE_CARRIER; + + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, + phy_data); + if (ret_val) + return ret_val; + } + + /* Workaround: Disable padding in Kumeran interface in the MAC + * and in the PHY to avoid CRC errors. + */ + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_INBAND_CTRL, + &phy_data); + if (ret_val) + return ret_val; + phy_data |= GG82563_ICR_DIS_PADDING; + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_INBAND_CTRL, + phy_data); + if (ret_val) + return ret_val; + } + + return E1000_SUCCESS; +} /******************************************************************** * Copper link setup for e1000_phy_m88 series. @@ -1524,6 +1712,7 @@ e1000_setup_copper_link(struct e1000_hw *hw) int32_t ret_val; uint16_t i; uint16_t phy_data; + uint16_t reg_data; DEBUGFUNC("e1000_setup_copper_link"); @@ -1532,6 +1721,22 @@ e1000_setup_copper_link(struct e1000_hw *hw) if(ret_val) return ret_val; + switch (hw->mac_type) { + case e1000_80003es2lan: + ret_val = e1000_read_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL, + ®_data); + if (ret_val) + return ret_val; + reg_data |= E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING; + ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL, + reg_data); + if (ret_val) + return ret_val; + break; + default: + break; + } + if (hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2) { ret_val = e1000_copper_link_igp_setup(hw); @@ -1541,6 +1746,10 @@ e1000_setup_copper_link(struct e1000_hw *hw) ret_val = e1000_copper_link_mgp_setup(hw); if(ret_val) return ret_val; + } else if (hw->phy_type == e1000_phy_gg82563) { + ret_val = e1000_copper_link_ggp_setup(hw); + if(ret_val) + return ret_val; } if(hw->autoneg) { @@ -1587,6 +1796,59 @@ e1000_setup_copper_link(struct e1000_hw *hw) return E1000_SUCCESS; } +/****************************************************************************** +* Configure the MAC-to-PHY interface for 10/100Mbps +* +* hw - Struct containing variables accessed by shared code +******************************************************************************/ +static int32_t +e1000_configure_kmrn_for_10_100(struct e1000_hw *hw) +{ + int32_t ret_val = E1000_SUCCESS; + uint32_t tipg; + uint16_t reg_data; + + DEBUGFUNC("e1000_configure_kmrn_for_10_100"); + + reg_data = E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT; + ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_HD_CTRL, + reg_data); + if (ret_val) + return ret_val; + + /* Configure Transmit Inter-Packet Gap */ + tipg = E1000_READ_REG(hw, TIPG); + tipg &= ~E1000_TIPG_IPGT_MASK; + tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_10_100; + E1000_WRITE_REG(hw, TIPG, tipg); + + return ret_val; +} + +static int32_t +e1000_configure_kmrn_for_1000(struct e1000_hw *hw) +{ + int32_t ret_val = E1000_SUCCESS; + uint16_t reg_data; + uint32_t tipg; + + DEBUGFUNC("e1000_configure_kmrn_for_1000"); + + reg_data = E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT; + ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_HD_CTRL, + reg_data); + if (ret_val) + return ret_val; + + /* Configure Transmit Inter-Packet Gap */ + tipg = E1000_READ_REG(hw, TIPG); + tipg &= ~E1000_TIPG_IPGT_MASK; + tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000; + E1000_WRITE_REG(hw, TIPG, tipg); + + return ret_val; +} + /****************************************************************************** * Configures PHY autoneg and flow control advertisement settings * @@ -1808,7 +2070,8 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw) /* Write the configured values back to the Device Control Reg. */ E1000_WRITE_REG(hw, CTRL, ctrl); - if (hw->phy_type == e1000_phy_m88) { + if ((hw->phy_type == e1000_phy_m88) || + (hw->phy_type == e1000_phy_gg82563)) { ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); if(ret_val) return ret_val; @@ -1877,7 +2140,8 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw) msec_delay(100); } if((i == 0) && - (hw->phy_type == e1000_phy_m88)) { + ((hw->phy_type == e1000_phy_m88) || + (hw->phy_type == e1000_phy_gg82563))) { /* We didn't get link. Reset the DSP and wait again for link. */ ret_val = e1000_phy_reset_dsp(hw); if(ret_val) { @@ -1936,6 +2200,27 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw) if(ret_val) return ret_val; } + } else if (hw->phy_type == e1000_phy_gg82563) { + /* The TX_CLK of the Extended PHY Specific Control Register defaults + * to 2.5MHz on a reset. We need to re-force it back to 25MHz, if + * we're not in a forced 10/duplex configuration. */ + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~GG82563_MSCR_TX_CLK_MASK; + if ((hw->forced_speed_duplex == e1000_10_full) || + (hw->forced_speed_duplex == e1000_10_half)) + phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ; + else + phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25MHZ; + + /* Also due to the reset, we need to enable CRS on Tx. */ + phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; + + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; } return E1000_SUCCESS; } @@ -2598,6 +2883,16 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw, } } + if ((hw->mac_type == e1000_80003es2lan) && + (hw->media_type == e1000_media_type_copper)) { + if (*speed == SPEED_1000) + ret_val = e1000_configure_kmrn_for_1000(hw); + else + ret_val = e1000_configure_kmrn_for_10_100(hw); + if (ret_val) + return ret_val; + } + return E1000_SUCCESS; } @@ -2773,6 +3068,72 @@ e1000_shift_in_mdi_bits(struct e1000_hw *hw) return data; } +int32_t +e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask) +{ + uint32_t swfw_sync = 0; + uint32_t swmask = mask; + uint32_t fwmask = mask << 16; + int32_t timeout = 200; + + DEBUGFUNC("e1000_swfw_sync_acquire"); + + if (!hw->swfw_sync_present) + return e1000_get_hw_eeprom_semaphore(hw); + + while(timeout) { + if (e1000_get_hw_eeprom_semaphore(hw)) + return -E1000_ERR_SWFW_SYNC; + + swfw_sync = E1000_READ_REG(hw, SW_FW_SYNC); + if (!(swfw_sync & (fwmask | swmask))) { + break; + } + + /* firmware currently using resource (fwmask) */ + /* or other software thread currently using resource (swmask) */ + e1000_put_hw_eeprom_semaphore(hw); + msec_delay_irq(5); + timeout--; + } + + if (!timeout) { + DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n"); + return -E1000_ERR_SWFW_SYNC; + } + + swfw_sync |= swmask; + E1000_WRITE_REG(hw, SW_FW_SYNC, swfw_sync); + + e1000_put_hw_eeprom_semaphore(hw); + return E1000_SUCCESS; +} + +void +e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask) +{ + uint32_t swfw_sync; + uint32_t swmask = mask; + + DEBUGFUNC("e1000_swfw_sync_release"); + + if (!hw->swfw_sync_present) { + e1000_put_hw_eeprom_semaphore(hw); + return; + } + + /* if (e1000_get_hw_eeprom_semaphore(hw)) + * return -E1000_ERR_SWFW_SYNC; */ + while (e1000_get_hw_eeprom_semaphore(hw) != E1000_SUCCESS); + /* empty */ + + swfw_sync = E1000_READ_REG(hw, SW_FW_SYNC); + swfw_sync &= ~swmask; + E1000_WRITE_REG(hw, SW_FW_SYNC, swfw_sync); + + e1000_put_hw_eeprom_semaphore(hw); +} + /***************************************************************************** * Reads the value from a PHY register, if the value is on a specific non zero * page, sets the page first. @@ -2785,22 +3146,55 @@ e1000_read_phy_reg(struct e1000_hw *hw, uint16_t *phy_data) { uint32_t ret_val; + uint16_t swfw; DEBUGFUNC("e1000_read_phy_reg"); + if ((hw->mac_type == e1000_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (e1000_swfw_sync_acquire(hw, swfw)) + return -E1000_ERR_SWFW_SYNC; + if((hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, (uint16_t)reg_addr); if(ret_val) { + e1000_swfw_sync_release(hw, swfw); return ret_val; } + } else if (hw->phy_type == e1000_phy_gg82563) { + if (((reg_addr & MAX_PHY_REG_ADDRESS) > MAX_PHY_MULTI_PAGE_REG) || + (hw->mac_type == e1000_80003es2lan)) { + /* Select Configuration Page */ + if ((reg_addr & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { + ret_val = e1000_write_phy_reg_ex(hw, GG82563_PHY_PAGE_SELECT, + (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT)); + } else { + /* Use Alternative Page Select register to access + * registers 30 and 31 + */ + ret_val = e1000_write_phy_reg_ex(hw, + GG82563_PHY_PAGE_SELECT_ALT, + (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT)); + } + + if (ret_val) { + e1000_swfw_sync_release(hw, swfw); + return ret_val; + } + } } ret_val = e1000_read_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr, phy_data); + e1000_swfw_sync_release(hw, swfw); return ret_val; } @@ -2891,22 +3285,55 @@ e1000_write_phy_reg(struct e1000_hw *hw, uint16_t phy_data) { uint32_t ret_val; + uint16_t swfw; DEBUGFUNC("e1000_write_phy_reg"); + if ((hw->mac_type == e1000_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (e1000_swfw_sync_acquire(hw, swfw)) + return -E1000_ERR_SWFW_SYNC; + if((hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, (uint16_t)reg_addr); if(ret_val) { + e1000_swfw_sync_release(hw, swfw); return ret_val; } + } else if (hw->phy_type == e1000_phy_gg82563) { + if (((reg_addr & MAX_PHY_REG_ADDRESS) > MAX_PHY_MULTI_PAGE_REG) || + (hw->mac_type == e1000_80003es2lan)) { + /* Select Configuration Page */ + if ((reg_addr & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { + ret_val = e1000_write_phy_reg_ex(hw, GG82563_PHY_PAGE_SELECT, + (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT)); + } else { + /* Use Alternative Page Select register to access + * registers 30 and 31 + */ + ret_val = e1000_write_phy_reg_ex(hw, + GG82563_PHY_PAGE_SELECT_ALT, + (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT)); + } + + if (ret_val) { + e1000_swfw_sync_release(hw, swfw); + return ret_val; + } + } } ret_val = e1000_write_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr, phy_data); + e1000_swfw_sync_release(hw, swfw); return ret_val; } @@ -2973,6 +3400,65 @@ e1000_write_phy_reg_ex(struct e1000_hw *hw, return E1000_SUCCESS; } +int32_t +e1000_read_kmrn_reg(struct e1000_hw *hw, + uint32_t reg_addr, + uint16_t *data) +{ + uint32_t reg_val; + uint16_t swfw; + DEBUGFUNC("e1000_read_kmrn_reg"); + + if ((hw->mac_type == e1000_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (e1000_swfw_sync_acquire(hw, swfw)) + return -E1000_ERR_SWFW_SYNC; + + /* Write register address */ + reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT) & + E1000_KUMCTRLSTA_OFFSET) | + E1000_KUMCTRLSTA_REN; + E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val); + udelay(2); + + /* Read the data returned */ + reg_val = E1000_READ_REG(hw, KUMCTRLSTA); + *data = (uint16_t)reg_val; + + e1000_swfw_sync_release(hw, swfw); + return E1000_SUCCESS; +} + +int32_t +e1000_write_kmrn_reg(struct e1000_hw *hw, + uint32_t reg_addr, + uint16_t data) +{ + uint32_t reg_val; + uint16_t swfw; + DEBUGFUNC("e1000_write_kmrn_reg"); + + if ((hw->mac_type == e1000_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (e1000_swfw_sync_acquire(hw, swfw)) + return -E1000_ERR_SWFW_SYNC; + + reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT) & + E1000_KUMCTRLSTA_OFFSET) | data; + E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val); + udelay(2); + + e1000_swfw_sync_release(hw, swfw); + return E1000_SUCCESS; +} /****************************************************************************** * Returns the PHY to the power-on reset state @@ -2985,6 +3471,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw) uint32_t ctrl, ctrl_ext; uint32_t led_ctrl; int32_t ret_val; + uint16_t swfw; DEBUGFUNC("e1000_phy_hw_reset"); @@ -2997,6 +3484,16 @@ e1000_phy_hw_reset(struct e1000_hw *hw) DEBUGOUT("Resetting Phy...\n"); if(hw->mac_type > e1000_82543) { + if ((hw->mac_type == e1000_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (e1000_swfw_sync_acquire(hw, swfw)) { + e1000_release_software_semaphore(hw); + return -E1000_ERR_SWFW_SYNC; + } /* Read the device control register and assert the E1000_CTRL_PHY_RST * bit. Then, take it out of reset. * For pre-e1000_82571 hardware, we delay for 10ms between the assert @@ -3017,6 +3514,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw) if (hw->mac_type >= e1000_82571) msec_delay(10); + e1000_swfw_sync_release(hw, swfw); } else { /* Read the Extended Device Control Register, assert the PHY_RESET_DIR * bit to put the PHY into reset. Then, take it out of reset. @@ -3043,6 +3541,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw) /* Wait for FW to finish PHY configuration. */ ret_val = e1000_get_phy_cfg_done(hw); + e1000_release_software_semaphore(hw); return ret_val; } @@ -3120,6 +3619,15 @@ e1000_detect_gig_phy(struct e1000_hw *hw) return E1000_SUCCESS; } + /* ESB-2 PHY reads require e1000_phy_gg82563 to be set because of a work- + * around that forces PHY page 0 to be set or the reads fail. The rest of + * the code in this routine uses e1000_read_phy_reg to read the PHY ID. + * So for ESB-2 we need to have this set so our reads won't fail. If the + * attached PHY is not a e1000_phy_gg82563, the routines below will figure + * this out as well. */ + if (hw->mac_type == e1000_80003es2lan) + hw->phy_type = e1000_phy_gg82563; + /* Read the PHY ID Registers to identify which PHY is onboard. */ ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high); if(ret_val) @@ -3157,6 +3665,9 @@ e1000_detect_gig_phy(struct e1000_hw *hw) case e1000_82573: if(hw->phy_id == M88E1111_I_PHY_ID) match = TRUE; break; + case e1000_80003es2lan: + if (hw->phy_id == GG82563_E_PHY_ID) match = TRUE; + break; default: DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type); return -E1000_ERR_CONFIG; @@ -3183,8 +3694,10 @@ e1000_phy_reset_dsp(struct e1000_hw *hw) DEBUGFUNC("e1000_phy_reset_dsp"); do { - ret_val = e1000_write_phy_reg(hw, 29, 0x001d); - if(ret_val) break; + if (hw->phy_type != e1000_phy_gg82563) { + ret_val = e1000_write_phy_reg(hw, 29, 0x001d); + if(ret_val) break; + } ret_val = e1000_write_phy_reg(hw, 30, 0x00c1); if(ret_val) break; ret_val = e1000_write_phy_reg(hw, 30, 0x0000); @@ -3316,8 +3829,17 @@ e1000_phy_m88_get_info(struct e1000_hw *hw, /* Cable Length Estimation and Local/Remote Receiver Information * are only valid at 1000 Mbps. */ - phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> - M88E1000_PSSR_CABLE_LENGTH_SHIFT); + if (hw->phy_type != e1000_phy_gg82563) { + phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT); + } else { + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_DSP_DISTANCE, + &phy_data); + if (ret_val) + return ret_val; + + phy_info->cable_length = phy_data & GG82563_DSPD_CABLE_LENGTH; + } ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); if(ret_val) @@ -3511,6 +4033,20 @@ e1000_init_eeprom_params(struct e1000_hw *hw) E1000_WRITE_REG(hw, EECD, eecd); } break; + case e1000_80003es2lan: + eeprom->type = e1000_eeprom_spi; + eeprom->opcode_bits = 8; + eeprom->delay_usec = 1; + if (eecd & E1000_EECD_ADDR_BITS) { + eeprom->page_size = 32; + eeprom->address_bits = 16; + } else { + eeprom->page_size = 8; + eeprom->address_bits = 8; + } + eeprom->use_eerd = TRUE; + eeprom->use_eewr = FALSE; + break; default: break; } @@ -3691,9 +4227,8 @@ e1000_acquire_eeprom(struct e1000_hw *hw) DEBUGFUNC("e1000_acquire_eeprom"); - if(e1000_get_hw_eeprom_semaphore(hw)) - return -E1000_ERR_EEPROM; - + if (e1000_swfw_sync_acquire(hw, E1000_SWFW_EEP_SM)) + return -E1000_ERR_SWFW_SYNC; eecd = E1000_READ_REG(hw, EECD); if (hw->mac_type != e1000_82573) { @@ -3712,7 +4247,7 @@ e1000_acquire_eeprom(struct e1000_hw *hw) eecd &= ~E1000_EECD_REQ; E1000_WRITE_REG(hw, EECD, eecd); DEBUGOUT("Could not acquire EEPROM grant\n"); - e1000_put_hw_eeprom_semaphore(hw); + e1000_swfw_sync_release(hw, E1000_SWFW_EEP_SM); return -E1000_ERR_EEPROM; } } @@ -3835,7 +4370,7 @@ e1000_release_eeprom(struct e1000_hw *hw) E1000_WRITE_REG(hw, EECD, eecd); } - e1000_put_hw_eeprom_semaphore(hw); + e1000_swfw_sync_release(hw, E1000_SWFW_EEP_SM); } /****************************************************************************** @@ -3914,6 +4449,8 @@ e1000_read_eeprom(struct e1000_hw *hw, if (e1000_is_onboard_nvm_eeprom(hw) == TRUE && hw->eeprom.use_eerd == FALSE) { switch (hw->mac_type) { + case e1000_80003es2lan: + break; default: /* Prepare the EEPROM for reading */ if (e1000_acquire_eeprom(hw) != E1000_SUCCESS) @@ -4031,6 +4568,9 @@ e1000_write_eeprom_eewr(struct e1000_hw *hw, uint32_t i = 0; int32_t error = 0; + if (e1000_swfw_sync_acquire(hw, E1000_SWFW_EEP_SM)) + return -E1000_ERR_SWFW_SYNC; + for (i = 0; i < words; i++) { register_value = (data[i] << E1000_EEPROM_RW_REG_DATA) | ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) | @@ -4050,6 +4590,7 @@ e1000_write_eeprom_eewr(struct e1000_hw *hw, } } + e1000_swfw_sync_release(hw, E1000_SWFW_EEP_SM); return error; } @@ -4091,6 +4632,8 @@ e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw) { uint32_t eecd = 0; + DEBUGFUNC("e1000_is_onboard_nvm_eeprom"); + if(hw->mac_type == e1000_82573) { eecd = E1000_READ_REG(hw, EECD); @@ -4517,6 +5060,7 @@ e1000_read_mac_addr(struct e1000_hw * hw) case e1000_82546: case e1000_82546_rev_3: case e1000_82571: + case e1000_80003es2lan: if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) hw->perm_mac_addr[5] ^= 0x01; break; @@ -4778,6 +5322,7 @@ e1000_rar_set(struct e1000_hw *hw, switch (hw->mac_type) { case e1000_82571: case e1000_82572: + case e1000_80003es2lan: if (hw->leave_av_bit_off == TRUE) break; default: @@ -5364,6 +5909,7 @@ e1000_get_bus_info(struct e1000_hw *hw) hw->bus_width = e1000_bus_width_pciex_1; break; case e1000_82571: + case e1000_80003es2lan: hw->bus_type = e1000_bus_type_pci_express; hw->bus_speed = e1000_bus_speed_2500; hw->bus_width = e1000_bus_width_pciex_4; @@ -5509,6 +6055,34 @@ e1000_get_cable_length(struct e1000_hw *hw, return -E1000_ERR_PHY; break; } + } else if (hw->phy_type == e1000_phy_gg82563) { + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_DSP_DISTANCE, + &phy_data); + if (ret_val) + return ret_val; + cable_length = phy_data & GG82563_DSPD_CABLE_LENGTH; + + switch (cable_length) { + case e1000_gg_cable_length_60: + *min_length = 0; + *max_length = e1000_igp_cable_length_60; + break; + case e1000_gg_cable_length_60_115: + *min_length = e1000_igp_cable_length_60; + *max_length = e1000_igp_cable_length_115; + break; + case e1000_gg_cable_length_115_150: + *min_length = e1000_igp_cable_length_115; + *max_length = e1000_igp_cable_length_150; + break; + case e1000_gg_cable_length_150: + *min_length = e1000_igp_cable_length_150; + *max_length = e1000_igp_cable_length_180; + break; + default: + return -E1000_ERR_PHY; + break; + } } else if(hw->phy_type == e1000_phy_igp) { /* For IGP PHY */ uint16_t agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = {IGP01E1000_PHY_AGC_A, @@ -5618,7 +6192,8 @@ e1000_check_polarity(struct e1000_hw *hw, DEBUGFUNC("e1000_check_polarity"); - if(hw->phy_type == e1000_phy_m88) { + if ((hw->phy_type == e1000_phy_m88) || + (hw->phy_type == e1000_phy_gg82563)) { /* return the Polarity bit in the Status register. */ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); @@ -5687,7 +6262,8 @@ e1000_check_downshift(struct e1000_hw *hw) return ret_val; hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0; - } else if(hw->phy_type == e1000_phy_m88) { + } else if ((hw->phy_type == e1000_phy_m88) || + (hw->phy_type == e1000_phy_gg82563)) { ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); if(ret_val) @@ -6720,6 +7296,7 @@ e1000_get_auto_rd_done(struct e1000_hw *hw) case e1000_82571: case e1000_82572: case e1000_82573: + case e1000_80003es2lan: while(timeout) { if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break; else msec_delay(1); @@ -6763,6 +7340,11 @@ e1000_get_phy_cfg_done(struct e1000_hw *hw) default: msec_delay(10); break; + case e1000_80003es2lan: + /* Separate *_CFG_DONE_* bit for each port */ + if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) + cfg_mask = E1000_EEPROM_CFG_DONE_PORT_1; + /* Fall Through */ case e1000_82571: case e1000_82572: while (timeout) { @@ -6805,6 +7387,11 @@ e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw) if(!hw->eeprom_semaphore_present) return E1000_SUCCESS; + if (hw->mac_type == e1000_80003es2lan) { + /* Get the SW semaphore. */ + if (e1000_get_software_semaphore(hw) != E1000_SUCCESS) + return -E1000_ERR_EEPROM; + } /* Get the FW semaphore. */ timeout = hw->eeprom.word_size + 1; @@ -6850,10 +7437,75 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw) return; swsm = E1000_READ_REG(hw, SWSM); + if (hw->mac_type == e1000_80003es2lan) { + /* Release both semaphores. */ + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + } else swsm &= ~(E1000_SWSM_SWESMBI); E1000_WRITE_REG(hw, SWSM, swsm); } +/*************************************************************************** + * + * Obtaining software semaphore bit (SMBI) before resetting PHY. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - E1000_ERR_RESET if fail to obtain semaphore. + * E1000_SUCCESS at any other case. + * + ***************************************************************************/ +int32_t +e1000_get_software_semaphore(struct e1000_hw *hw) +{ + int32_t timeout = hw->eeprom.word_size + 1; + uint32_t swsm; + + DEBUGFUNC("e1000_get_software_semaphore"); + + if (hw->mac_type != e1000_80003es2lan) + return E1000_SUCCESS; + + while(timeout) { + swsm = E1000_READ_REG(hw, SWSM); + /* If SMBI bit cleared, it is now set and we hold the semaphore */ + if(!(swsm & E1000_SWSM_SMBI)) + break; + msec_delay_irq(1); + timeout--; + } + + if(!timeout) { + DEBUGOUT("Driver can't access device - SMBI bit is set.\n"); + return -E1000_ERR_RESET; + } + + return E1000_SUCCESS; +} + +/*************************************************************************** + * + * Release semaphore bit (SMBI). + * + * hw: Struct containing variables accessed by shared code + * + ***************************************************************************/ +void +e1000_release_software_semaphore(struct e1000_hw *hw) +{ + uint32_t swsm; + + DEBUGFUNC("e1000_release_software_semaphore"); + + if (hw->mac_type != e1000_80003es2lan) + return; + + swsm = E1000_READ_REG(hw, SWSM); + /* Release the SW semaphores.*/ + swsm &= ~E1000_SWSM_SMBI; + E1000_WRITE_REG(hw, SWSM, swsm); +} + /****************************************************************************** * Checks if PHY reset is blocked due to SOL/IDER session, for example. * Returning E1000_BLK_PHY_RESET isn't necessarily an error. But it's up to @@ -6890,6 +7542,7 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw) case e1000_82571: case e1000_82572: case e1000_82573: + case e1000_80003es2lan: fwsm = E1000_READ_REG(hw, FWSM); if((fwsm & E1000_FWSM_MODE_MASK) != 0) return TRUE; diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index f565b201c49..947a156bd70 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -60,6 +60,7 @@ typedef enum { e1000_82571, e1000_82572, e1000_82573, + e1000_80003es2lan, e1000_num_macs } e1000_mac_type; @@ -138,6 +139,13 @@ typedef enum { e1000_cable_length_undefined = 0xFF } e1000_cable_length; +typedef enum { + e1000_gg_cable_length_60 = 0, + e1000_gg_cable_length_60_115 = 1, + e1000_gg_cable_length_115_150 = 2, + e1000_gg_cable_length_150 = 4 +} e1000_gg_cable_length; + typedef enum { e1000_igp_cable_length_10 = 10, e1000_igp_cable_length_20 = 20, @@ -208,6 +216,7 @@ typedef enum { e1000_phy_m88 = 0, e1000_phy_igp, e1000_phy_igp_2, + e1000_phy_gg82563, e1000_phy_undefined = 0xFF } e1000_phy_type; @@ -281,6 +290,7 @@ typedef enum { #define E1000_ERR_MASTER_REQUESTS_PENDING 10 #define E1000_ERR_HOST_INTERFACE_COMMAND 11 #define E1000_BLK_PHY_RESET 12 +#define E1000_ERR_SWFW_SYNC 13 /* Function prototypes */ /* Initialization */ @@ -304,6 +314,8 @@ int32_t e1000_phy_hw_reset(struct e1000_hw *hw); int32_t e1000_phy_reset(struct e1000_hw *hw); int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info); int32_t e1000_validate_mdi_setting(struct e1000_hw *hw); +int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data); +int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data); /* EEPROM Functions */ int32_t e1000_init_eeprom_params(struct e1000_hw *hw); @@ -454,6 +466,8 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw); #define E1000_DEV_ID_82573E_IAMT 0x108C #define E1000_DEV_ID_82573L 0x109A #define E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3 0x10B5 +#define E1000_DEV_ID_80003ES2LAN_COPPER_DPT 0x1096 +#define E1000_DEV_ID_80003ES2LAN_SERDES_DPT 0x1098 #define NODE_ADDRESS_SIZE 6 @@ -850,6 +864,7 @@ struct e1000_ffvt_entry { #define E1000_TXCW 0x00178 /* TX Configuration Word - RW */ #define E1000_RXCW 0x00180 /* RX Configuration Word - RO */ #define E1000_TCTL 0x00400 /* TX Control - RW */ +#define E1000_TCTL_EXT 0x00404 /* Extended TX Control - RW */ #define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */ #define E1000_TBT 0x00448 /* TX Burst Timer - RW */ #define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */ @@ -996,6 +1011,11 @@ struct e1000_ffvt_entry { #define E1000_FFMT 0x09000 /* Flexible Filter Mask Table - RW Array */ #define E1000_FFVT 0x09800 /* Flexible Filter Value Table - RW Array */ +#define E1000_KUMCTRLSTA 0x00034 /* MAC-PHY interface - RW */ +#define E1000_MDPHYA 0x0003C /* PHY address - RW */ +#define E1000_MANC2H 0x05860 /* Managment Control To Host - RW */ +#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ + #define E1000_GCR 0x05B00 /* PCI-Ex Control */ #define E1000_GSCL_1 0x05B10 /* PCI-Ex Statistic Control #1 */ #define E1000_GSCL_2 0x05B14 /* PCI-Ex Statistic Control #2 */ @@ -1065,6 +1085,7 @@ struct e1000_ffvt_entry { #define E1000_82542_RXCW E1000_RXCW #define E1000_82542_MTA 0x00200 #define E1000_82542_TCTL E1000_TCTL +#define E1000_82542_TCTL_EXT E1000_TCTL_EXT #define E1000_82542_TIPG E1000_TIPG #define E1000_82542_TDBAL 0x00420 #define E1000_82542_TDBAH 0x00424 @@ -1212,6 +1233,8 @@ struct e1000_ffvt_entry { #define E1000_82542_RSSRK E1000_RSSRK #define E1000_82542_RSSIM E1000_RSSIM #define E1000_82542_RSSIR E1000_RSSIR +#define E1000_82542_KUMCTRLSTA E1000_KUMCTRLSTA +#define E1000_82542_SW_FW_SYNC E1000_SW_FW_SYNC /* Statistics counters collected by the MAC */ struct e1000_hw_stats { @@ -1303,6 +1326,7 @@ struct e1000_hw { e1000_ffe_config ffe_config_state; uint32_t asf_firmware_present; uint32_t eeprom_semaphore_present; + uint32_t swfw_sync_present; unsigned long io_base; uint32_t phy_id; uint32_t phy_revision; @@ -1394,6 +1418,8 @@ struct e1000_hw { #define E1000_CTRL_FRCDPX 0x00001000 /* Force Duplex */ #define E1000_CTRL_D_UD_EN 0x00002000 /* Dock/Undock enable */ #define E1000_CTRL_D_UD_POLARITY 0x00004000 /* Defined polarity of Dock/Undock indication in SDP[0] */ +#define E1000_CTRL_FORCE_PHY_RESET 0x00008000 /* Reset both PHY ports, through PHYRST_N pin */ +#define E1000_CTRL_EXT_LINK_EN 0x00010000 /* enable link status from external LINK_0 and LINK_1 pins */ #define E1000_CTRL_SWDPIN0 0x00040000 /* SWDPIN 0 value */ #define E1000_CTRL_SWDPIN1 0x00080000 /* SWDPIN 1 value */ #define E1000_CTRL_SWDPIN2 0x00100000 /* SWDPIN 2 value */ @@ -1430,6 +1456,16 @@ struct e1000_hw { #define E1000_STATUS_BUS64 0x00001000 /* In 64 bit slot */ #define E1000_STATUS_PCIX_MODE 0x00002000 /* PCI-X mode */ #define E1000_STATUS_PCIX_SPEED 0x0000C000 /* PCI-X bus speed */ +#define E1000_STATUS_BMC_SKU_0 0x00100000 /* BMC USB redirect disabled */ +#define E1000_STATUS_BMC_SKU_1 0x00200000 /* BMC SRAM disabled */ +#define E1000_STATUS_BMC_SKU_2 0x00400000 /* BMC SDRAM disabled */ +#define E1000_STATUS_BMC_CRYPTO 0x00800000 /* BMC crypto disabled */ +#define E1000_STATUS_BMC_LITE 0x01000000 /* BMC external code execution disabled */ +#define E1000_STATUS_RGMII_ENABLE 0x02000000 /* RGMII disabled */ +#define E1000_STATUS_FUSE_8 0x04000000 +#define E1000_STATUS_FUSE_9 0x08000000 +#define E1000_STATUS_SERDES0_DIS 0x10000000 /* SERDES disabled on port 0 */ +#define E1000_STATUS_SERDES1_DIS 0x20000000 /* SERDES disabled on port 1 */ /* Constants used to intrepret the masked PCI-X bus speed. */ #define E1000_STATUS_PCIX_SPEED_66 0x00000000 /* PCI-X bus speed 50-66 MHz */ @@ -1507,6 +1543,8 @@ struct e1000_hw { #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000 #define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000 #define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000 +#define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000 +#define E1000_CTRL_EXT_LINK_MODE_SERDES 0x00C00000 #define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000 #define E1000_CTRL_EXT_WR_WMARK_256 0x00000000 #define E1000_CTRL_EXT_WR_WMARK_320 0x01000000 @@ -1516,6 +1554,9 @@ struct e1000_hw { #define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */ #define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */ #define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */ +#define E1000_CRTL_EXT_PB_PAREN 0x01000000 /* packet buffer parity error detection enabled */ +#define E1000_CTRL_EXT_DF_PAREN 0x02000000 /* descriptor FIFO parity error detection enable */ +#define E1000_CTRL_EXT_GHOST_PAREN 0x40000000 /* MDI Control */ #define E1000_MDIC_DATA_MASK 0x0000FFFF @@ -1529,6 +1570,32 @@ struct e1000_hw { #define E1000_MDIC_INT_EN 0x20000000 #define E1000_MDIC_ERROR 0x40000000 +#define E1000_KUMCTRLSTA_MASK 0x0000FFFF +#define E1000_KUMCTRLSTA_OFFSET 0x001F0000 +#define E1000_KUMCTRLSTA_OFFSET_SHIFT 16 +#define E1000_KUMCTRLSTA_REN 0x00200000 + +#define E1000_KUMCTRLSTA_OFFSET_FIFO_CTRL 0x00000000 +#define E1000_KUMCTRLSTA_OFFSET_CTRL 0x00000001 +#define E1000_KUMCTRLSTA_OFFSET_INB_CTRL 0x00000002 +#define E1000_KUMCTRLSTA_OFFSET_DIAG 0x00000003 +#define E1000_KUMCTRLSTA_OFFSET_TIMEOUTS 0x00000004 +#define E1000_KUMCTRLSTA_OFFSET_INB_PARAM 0x00000009 +#define E1000_KUMCTRLSTA_OFFSET_HD_CTRL 0x00000010 +#define E1000_KUMCTRLSTA_OFFSET_M2P_SERDES 0x0000001E +#define E1000_KUMCTRLSTA_OFFSET_M2P_MODES 0x0000001F + +/* FIFO Control */ +#define E1000_KUMCTRLSTA_FIFO_CTRL_RX_BYPASS 0x00000008 +#define E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS 0x00000800 + +/* In-Band Control */ +#define E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING 0x00000010 + +/* Half-Duplex Control */ +#define E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT 0x00000004 +#define E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT 0x00000000 + /* LED Control */ #define E1000_LEDCTL_LED0_MODE_MASK 0x0000000F #define E1000_LEDCTL_LED0_MODE_SHIFT 0 @@ -1591,6 +1658,13 @@ struct e1000_hw { #define E1000_ICR_MNG 0x00040000 /* Manageability event */ #define E1000_ICR_DOCK 0x00080000 /* Dock/Undock */ #define E1000_ICR_INT_ASSERTED 0x80000000 /* If this bit asserted, the driver should claim the interrupt */ +#define E1000_ICR_RXD_FIFO_PAR0 0x00100000 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_ICR_TXD_FIFO_PAR0 0x00200000 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_ICR_HOST_ARB_PAR 0x00400000 /* host arb read buffer parity error */ +#define E1000_ICR_PB_PAR 0x00800000 /* packet buffer parity error */ +#define E1000_ICR_RXD_FIFO_PAR1 0x01000000 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_ICR_TXD_FIFO_PAR1 0x02000000 /* queue 1 Tx descriptor FIFO parity error */ +#define E1000_ICR_ALL_PARITY 0x03F00000 /* all parity error bits */ /* Interrupt Cause Set */ #define E1000_ICS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -1611,6 +1685,12 @@ struct e1000_hw { #define E1000_ICS_ACK E1000_ICR_ACK /* Receive Ack frame */ #define E1000_ICS_MNG E1000_ICR_MNG /* Manageability event */ #define E1000_ICS_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_ICS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_ICS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_ICS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ +#define E1000_ICS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ +#define E1000_ICS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_ICS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ /* Interrupt Mask Set */ #define E1000_IMS_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -1631,6 +1711,12 @@ struct e1000_hw { #define E1000_IMS_ACK E1000_ICR_ACK /* Receive Ack frame */ #define E1000_IMS_MNG E1000_ICR_MNG /* Manageability event */ #define E1000_IMS_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_IMS_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_IMS_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_IMS_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ +#define E1000_IMS_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ +#define E1000_IMS_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_IMS_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ /* Interrupt Mask Clear */ #define E1000_IMC_TXDW E1000_ICR_TXDW /* Transmit desc written back */ @@ -1651,6 +1737,12 @@ struct e1000_hw { #define E1000_IMC_ACK E1000_ICR_ACK /* Receive Ack frame */ #define E1000_IMC_MNG E1000_ICR_MNG /* Manageability event */ #define E1000_IMC_DOCK E1000_ICR_DOCK /* Dock/Undock */ +#define E1000_IMC_RXD_FIFO_PAR0 E1000_ICR_RXD_FIFO_PAR0 /* queue 0 Rx descriptor FIFO parity error */ +#define E1000_IMC_TXD_FIFO_PAR0 E1000_ICR_TXD_FIFO_PAR0 /* queue 0 Tx descriptor FIFO parity error */ +#define E1000_IMC_HOST_ARB_PAR E1000_ICR_HOST_ARB_PAR /* host arb read buffer parity error */ +#define E1000_IMC_PB_PAR E1000_ICR_PB_PAR /* packet buffer parity error */ +#define E1000_IMC_RXD_FIFO_PAR1 E1000_ICR_RXD_FIFO_PAR1 /* queue 1 Rx descriptor FIFO parity error */ +#define E1000_IMC_TXD_FIFO_PAR1 E1000_ICR_TXD_FIFO_PAR1 /* queue 1 Tx descriptor FIFO parity error */ /* Receive Control */ #define E1000_RCTL_RST 0x00000001 /* Software reset */ @@ -1720,6 +1812,12 @@ struct e1000_hw { #define E1000_PSRCTL_BSIZE2_SHIFT 6 /* Shift _left_ 6 */ #define E1000_PSRCTL_BSIZE3_SHIFT 14 /* Shift _left_ 14 */ +/* SW_W_SYNC definitions */ +#define E1000_SWFW_EEP_SM 0x0001 +#define E1000_SWFW_PHY0_SM 0x0002 +#define E1000_SWFW_PHY1_SM 0x0004 +#define E1000_SWFW_MAC_CSR_SM 0x0008 + /* Receive Descriptor */ #define E1000_RDT_DELAY 0x0000ffff /* Delay timer (1=1024us) */ #define E1000_RDT_FPDB 0x80000000 /* Flush descriptor block */ @@ -1798,6 +1896,11 @@ struct e1000_hw { #define E1000_TCTL_RTLC 0x01000000 /* Re-transmit on late collision */ #define E1000_TCTL_NRTU 0x02000000 /* No Re-transmit on underrun */ #define E1000_TCTL_MULR 0x10000000 /* Multiple request support */ +/* Extended Transmit Control */ +#define E1000_TCTL_EXT_BST_MASK 0x000003FF /* Backoff Slot Time */ +#define E1000_TCTL_EXT_GCEX_MASK 0x000FFC00 /* Gigabit Carry Extend Padding */ + +#define DEFAULT_80003ES2LAN_TCTL_EXT_GCEX 0x00010000 /* Receive Checksum Control */ #define E1000_RXCSUM_PCSS_MASK 0x000000FF /* Packet Checksum Start */ @@ -2044,6 +2147,7 @@ struct e1000_host_command_info { #define EEPROM_CHECKSUM_REG 0x003F #define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */ +#define E1000_EEPROM_CFG_DONE_PORT_1 0x00080000 /* ...for second port */ /* Word definitions for ID LED Settings */ #define ID_LED_RESERVED_0000 0x0000 @@ -2132,8 +2236,11 @@ struct e1000_host_command_info { #define DEFAULT_82542_TIPG_IPGR2 10 #define DEFAULT_82543_TIPG_IPGR2 6 +#define DEFAULT_80003ES2LAN_TIPG_IPGR2 7 #define E1000_TIPG_IPGR2_SHIFT 20 +#define DEFAULT_80003ES2LAN_TIPG_IPGT_10_100 0x00000009 +#define DEFAULT_80003ES2LAN_TIPG_IPGT_1000 0x00000008 #define E1000_TXDMAC_DPP 0x00000001 /* Adaptive IFS defines */ @@ -2374,6 +2481,78 @@ struct e1000_host_command_info { #define IGP01E1000_ANALOG_REGS_PAGE 0x20C0 +/* Bits... + * 15-5: page + * 4-0: register offset + */ +#define GG82563_PAGE_SHIFT 5 +#define GG82563_REG(page, reg) \ + (((page) << GG82563_PAGE_SHIFT) | ((reg) & MAX_PHY_REG_ADDRESS)) +#define GG82563_MIN_ALT_REG 30 + +/* GG82563 Specific Registers */ +#define GG82563_PHY_SPEC_CTRL \ + GG82563_REG(0, 16) /* PHY Specific Control */ +#define GG82563_PHY_SPEC_STATUS \ + GG82563_REG(0, 17) /* PHY Specific Status */ +#define GG82563_PHY_INT_ENABLE \ + GG82563_REG(0, 18) /* Interrupt Enable */ +#define GG82563_PHY_SPEC_STATUS_2 \ + GG82563_REG(0, 19) /* PHY Specific Status 2 */ +#define GG82563_PHY_RX_ERR_CNTR \ + GG82563_REG(0, 21) /* Receive Error Counter */ +#define GG82563_PHY_PAGE_SELECT \ + GG82563_REG(0, 22) /* Page Select */ +#define GG82563_PHY_SPEC_CTRL_2 \ + GG82563_REG(0, 26) /* PHY Specific Control 2 */ +#define GG82563_PHY_PAGE_SELECT_ALT \ + GG82563_REG(0, 29) /* Alternate Page Select */ +#define GG82563_PHY_TEST_CLK_CTRL \ + GG82563_REG(0, 30) /* Test Clock Control (use reg. 29 to select) */ + +#define GG82563_PHY_MAC_SPEC_CTRL \ + GG82563_REG(2, 21) /* MAC Specific Control Register */ +#define GG82563_PHY_MAC_SPEC_CTRL_2 \ + GG82563_REG(2, 26) /* MAC Specific Control 2 */ + +#define GG82563_PHY_DSP_DISTANCE \ + GG82563_REG(5, 26) /* DSP Distance */ + +/* Page 193 - Port Control Registers */ +#define GG82563_PHY_KMRN_MODE_CTRL \ + GG82563_REG(193, 16) /* Kumeran Mode Control */ +#define GG82563_PHY_PORT_RESET \ + GG82563_REG(193, 17) /* Port Reset */ +#define GG82563_PHY_REVISION_ID \ + GG82563_REG(193, 18) /* Revision ID */ +#define GG82563_PHY_DEVICE_ID \ + GG82563_REG(193, 19) /* Device ID */ +#define GG82563_PHY_PWR_MGMT_CTRL \ + GG82563_REG(193, 20) /* Power Management Control */ +#define GG82563_PHY_RATE_ADAPT_CTRL \ + GG82563_REG(193, 25) /* Rate Adaptation Control */ + +/* Page 194 - KMRN Registers */ +#define GG82563_PHY_KMRN_FIFO_CTRL_STAT \ + GG82563_REG(194, 16) /* FIFO's Control/Status */ +#define GG82563_PHY_KMRN_CTRL \ + GG82563_REG(194, 17) /* Control */ +#define GG82563_PHY_INBAND_CTRL \ + GG82563_REG(194, 18) /* Inband Control */ +#define GG82563_PHY_KMRN_DIAGNOSTIC \ + GG82563_REG(194, 19) /* Diagnostic */ +#define GG82563_PHY_ACK_TIMEOUTS \ + GG82563_REG(194, 20) /* Acknowledge Timeouts */ +#define GG82563_PHY_ADV_ABILITY \ + GG82563_REG(194, 21) /* Advertised Ability */ +#define GG82563_PHY_LINK_PARTNER_ADV_ABILITY \ + GG82563_REG(194, 23) /* Link Partner Advertised Ability */ +#define GG82563_PHY_ADV_NEXT_PAGE \ + GG82563_REG(194, 24) /* Advertised Next Page */ +#define GG82563_PHY_LINK_PARTNER_ADV_NEXT_PAGE \ + GG82563_REG(194, 25) /* Link Partner Advertised Next page */ +#define GG82563_PHY_KMRN_MISC \ + GG82563_REG(194, 26) /* Misc. */ /* PHY Control Register */ #define MII_CR_SPEED_SELECT_MSB 0x0040 /* bits 6,13: 10=1000, 01=100, 00=10 */ @@ -2687,6 +2866,113 @@ struct e1000_host_command_info { #define IGP01E1000_ANALOG_FUSE_FINE_1 0x0080 #define IGP01E1000_ANALOG_FUSE_FINE_10 0x0500 +/* GG82563 PHY Specific Status Register (Page 0, Register 16 */ +#define GG82563_PSCR_DISABLE_JABBER 0x0001 /* 1=Disable Jabber */ +#define GG82563_PSCR_POLARITY_REVERSAL_DISABLE 0x0002 /* 1=Polarity Reversal Disabled */ +#define GG82563_PSCR_POWER_DOWN 0x0004 /* 1=Power Down */ +#define GG82563_PSCR_COPPER_TRANSMITER_DISABLE 0x0008 /* 1=Transmitter Disabled */ +#define GG82563_PSCR_CROSSOVER_MODE_MASK 0x0060 +#define GG82563_PSCR_CROSSOVER_MODE_MDI 0x0000 /* 00=Manual MDI configuration */ +#define GG82563_PSCR_CROSSOVER_MODE_MDIX 0x0020 /* 01=Manual MDIX configuration */ +#define GG82563_PSCR_CROSSOVER_MODE_AUTO 0x0060 /* 11=Automatic crossover */ +#define GG82563_PSCR_ENALBE_EXTENDED_DISTANCE 0x0080 /* 1=Enable Extended Distance */ +#define GG82563_PSCR_ENERGY_DETECT_MASK 0x0300 +#define GG82563_PSCR_ENERGY_DETECT_OFF 0x0000 /* 00,01=Off */ +#define GG82563_PSCR_ENERGY_DETECT_RX 0x0200 /* 10=Sense on Rx only (Energy Detect) */ +#define GG82563_PSCR_ENERGY_DETECT_RX_TM 0x0300 /* 11=Sense and Tx NLP */ +#define GG82563_PSCR_FORCE_LINK_GOOD 0x0400 /* 1=Force Link Good */ +#define GG82563_PSCR_DOWNSHIFT_ENABLE 0x0800 /* 1=Enable Downshift */ +#define GG82563_PSCR_DOWNSHIFT_COUNTER_MASK 0x7000 +#define GG82563_PSCR_DOWNSHIFT_COUNTER_SHIFT 12 + +/* PHY Specific Status Register (Page 0, Register 17) */ +#define GG82563_PSSR_JABBER 0x0001 /* 1=Jabber */ +#define GG82563_PSSR_POLARITY 0x0002 /* 1=Polarity Reversed */ +#define GG82563_PSSR_LINK 0x0008 /* 1=Link is Up */ +#define GG82563_PSSR_ENERGY_DETECT 0x0010 /* 1=Sleep, 0=Active */ +#define GG82563_PSSR_DOWNSHIFT 0x0020 /* 1=Downshift */ +#define GG82563_PSSR_CROSSOVER_STATUS 0x0040 /* 1=MDIX, 0=MDI */ +#define GG82563_PSSR_RX_PAUSE_ENABLED 0x0100 /* 1=Receive Pause Enabled */ +#define GG82563_PSSR_TX_PAUSE_ENABLED 0x0200 /* 1=Transmit Pause Enabled */ +#define GG82563_PSSR_LINK_UP 0x0400 /* 1=Link Up */ +#define GG82563_PSSR_SPEED_DUPLEX_RESOLVED 0x0800 /* 1=Resolved */ +#define GG82563_PSSR_PAGE_RECEIVED 0x1000 /* 1=Page Received */ +#define GG82563_PSSR_DUPLEX 0x2000 /* 1-Full-Duplex */ +#define GG82563_PSSR_SPEED_MASK 0xC000 +#define GG82563_PSSR_SPEED_10MBPS 0x0000 /* 00=10Mbps */ +#define GG82563_PSSR_SPEED_100MBPS 0x4000 /* 01=100Mbps */ +#define GG82563_PSSR_SPEED_1000MBPS 0x8000 /* 10=1000Mbps */ + +/* PHY Specific Status Register 2 (Page 0, Register 19) */ +#define GG82563_PSSR2_JABBER 0x0001 /* 1=Jabber */ +#define GG82563_PSSR2_POLARITY_CHANGED 0x0002 /* 1=Polarity Changed */ +#define GG82563_PSSR2_ENERGY_DETECT_CHANGED 0x0010 /* 1=Energy Detect Changed */ +#define GG82563_PSSR2_DOWNSHIFT_INTERRUPT 0x0020 /* 1=Downshift Detected */ +#define GG82563_PSSR2_MDI_CROSSOVER_CHANGE 0x0040 /* 1=Crossover Changed */ +#define GG82563_PSSR2_FALSE_CARRIER 0x0100 /* 1=False Carrier */ +#define GG82563_PSSR2_SYMBOL_ERROR 0x0200 /* 1=Symbol Error */ +#define GG82563_PSSR2_LINK_STATUS_CHANGED 0x0400 /* 1=Link Status Changed */ +#define GG82563_PSSR2_AUTO_NEG_COMPLETED 0x0800 /* 1=Auto-Neg Completed */ +#define GG82563_PSSR2_PAGE_RECEIVED 0x1000 /* 1=Page Received */ +#define GG82563_PSSR2_DUPLEX_CHANGED 0x2000 /* 1=Duplex Changed */ +#define GG82563_PSSR2_SPEED_CHANGED 0x4000 /* 1=Speed Changed */ +#define GG82563_PSSR2_AUTO_NEG_ERROR 0x8000 /* 1=Auto-Neg Error */ + +/* PHY Specific Control Register 2 (Page 0, Register 26) */ +#define GG82563_PSCR2_10BT_POLARITY_FORCE 0x0002 /* 1=Force Negative Polarity */ +#define GG82563_PSCR2_1000MB_TEST_SELECT_MASK 0x000C +#define GG82563_PSCR2_1000MB_TEST_SELECT_NORMAL 0x0000 /* 00,01=Normal Operation */ +#define GG82563_PSCR2_1000MB_TEST_SELECT_112NS 0x0008 /* 10=Select 112ns Sequence */ +#define GG82563_PSCR2_1000MB_TEST_SELECT_16NS 0x000C /* 11=Select 16ns Sequence */ +#define GG82563_PSCR2_REVERSE_AUTO_NEG 0x2000 /* 1=Reverse Auto-Negotiation */ +#define GG82563_PSCR2_1000BT_DISABLE 0x4000 /* 1=Disable 1000BASE-T */ +#define GG82563_PSCR2_TRANSMITER_TYPE_MASK 0x8000 +#define GG82563_PSCR2_TRANSMITTER_TYPE_CLASS_B 0x0000 /* 0=Class B */ +#define GG82563_PSCR2_TRANSMITTER_TYPE_CLASS_A 0x8000 /* 1=Class A */ + +/* MAC Specific Control Register (Page 2, Register 21) */ +/* Tx clock speed for Link Down and 1000BASE-T for the following speeds */ +#define GG82563_MSCR_TX_CLK_MASK 0x0007 +#define GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ 0x0004 +#define GG82563_MSCR_TX_CLK_100MBPS_25MHZ 0x0005 +#define GG82563_MSCR_TX_CLK_1000MBPS_2_5MHZ 0x0006 +#define GG82563_MSCR_TX_CLK_1000MBPS_25MHZ 0x0007 + +#define GG82563_MSCR_ASSERT_CRS_ON_TX 0x0010 /* 1=Assert */ + +/* DSP Distance Register (Page 5, Register 26) */ +#define GG82563_DSPD_CABLE_LENGTH 0x0007 /* 0 = <50M; + 1 = 50-80M; + 2 = 80-110M; + 3 = 110-140M; + 4 = >140M */ + +/* Kumeran Mode Control Register (Page 193, Register 16) */ +#define GG82563_KMCR_PHY_LEDS_EN 0x0020 /* 1=PHY LEDs, 0=Kumeran Inband LEDs */ +#define GG82563_KMCR_FORCE_LINK_UP 0x0040 /* 1=Force Link Up */ +#define GG82563_KMCR_SUPPRESS_SGMII_EPD_EXT 0x0080 +#define GG82563_KMCR_MDIO_BUS_SPEED_SELECT_MASK 0x0400 +#define GG82563_KMCR_MDIO_BUS_SPEED_SELECT 0x0400 /* 1=6.25MHz, 0=0.8MHz */ +#define GG82563_KMCR_PASS_FALSE_CARRIER 0x0800 + +/* Power Management Control Register (Page 193, Register 20) */ +#define GG82563_PMCR_ENABLE_ELECTRICAL_IDLE 0x0001 /* 1=Enalbe SERDES Electrical Idle */ +#define GG82563_PMCR_DISABLE_PORT 0x0002 /* 1=Disable Port */ +#define GG82563_PMCR_DISABLE_SERDES 0x0004 /* 1=Disable SERDES */ +#define GG82563_PMCR_REVERSE_AUTO_NEG 0x0008 /* 1=Enable Reverse Auto-Negotiation */ +#define GG82563_PMCR_DISABLE_1000_NON_D0 0x0010 /* 1=Disable 1000Mbps Auto-Neg in non D0 */ +#define GG82563_PMCR_DISABLE_1000 0x0020 /* 1=Disable 1000Mbps Auto-Neg Always */ +#define GG82563_PMCR_REVERSE_AUTO_NEG_D0A 0x0040 /* 1=Enable D0a Reverse Auto-Negotiation */ +#define GG82563_PMCR_FORCE_POWER_STATE 0x0080 /* 1=Force Power State */ +#define GG82563_PMCR_PROGRAMMED_POWER_STATE_MASK 0x0300 +#define GG82563_PMCR_PROGRAMMED_POWER_STATE_DR 0x0000 /* 00=Dr */ +#define GG82563_PMCR_PROGRAMMED_POWER_STATE_D0U 0x0100 /* 01=D0u */ +#define GG82563_PMCR_PROGRAMMED_POWER_STATE_D0A 0x0200 /* 10=D0a */ +#define GG82563_PMCR_PROGRAMMED_POWER_STATE_D3 0x0300 /* 11=D3 */ + +/* In-Band Control Register (Page 194, Register 18) */ +#define GG82563_ICR_DIS_PADDING 0x0010 /* Disable Padding Use */ + /* Bit definitions for valid PHY IDs. */ /* I = Integrated @@ -2701,6 +2987,7 @@ struct e1000_host_command_info { #define M88E1011_I_REV_4 0x04 #define M88E1111_I_PHY_ID 0x01410CC0 #define L1LXT971A_PHY_ID 0x001378E0 +#define GG82563_E_PHY_ID 0x01410CA0 /* Miscellaneous PHY bit definitions. */ #define PHY_PREAMBLE 0xFFFFFFFF diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index e80378a220d..3acbffd5bde 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -157,9 +157,12 @@ static struct pci_device_id e1000_pci_tbl[] = { INTEL_E1000_ETHERNET_DEVICE(0x108A), INTEL_E1000_ETHERNET_DEVICE(0x108B), INTEL_E1000_ETHERNET_DEVICE(0x108C), + INTEL_E1000_ETHERNET_DEVICE(0x1096), + INTEL_E1000_ETHERNET_DEVICE(0x1098), INTEL_E1000_ETHERNET_DEVICE(0x1099), INTEL_E1000_ETHERNET_DEVICE(0x109A), INTEL_E1000_ETHERNET_DEVICE(0x10B5), + INTEL_E1000_ETHERNET_DEVICE(0x10B9), /* required last entry */ {0,} }; @@ -575,6 +578,7 @@ e1000_reset(struct e1000_adapter *adapter) break; case e1000_82571: case e1000_82572: + case e1000_80003es2lan: pba = E1000_PBA_38K; break; case e1000_82573: @@ -852,6 +856,7 @@ e1000_probe(struct pci_dev *pdev, case e1000_82546: case e1000_82546_rev_3: case e1000_82571: + case e1000_80003es2lan: if (E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_FUNC_1){ e1000_read_eeprom(&adapter->hw, EEPROM_INIT_CONTROL3_PORT_B, 1, &eeprom_data); -- cgit v1.2.3 From 8704163987882f8b989e8143ad1f87c6b7229a13 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:21:24 -0800 Subject: e1000: Fixed the following issues with ESB2 (requires ESB2 support): - Add restriction for ESB2 to MTU size <=9216 - Removed FIFO errors which were not being used - Fixed issues with loopback - Power management change for saving state and config space - WA to disable recieves and reset device on link loss. Reset needed to be done outside the interrupt context - modified existing tx_timeout_task Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000.h | 4 +-- drivers/net/e1000/e1000_ethtool.c | 10 +++++- drivers/net/e1000/e1000_main.c | 65 ++++++++++++++++++++++++++++++++------- 3 files changed, 65 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 3319c19cbee..d4266f18bbd 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -252,8 +252,8 @@ struct e1000_adapter { spinlock_t tx_queue_lock; #endif atomic_t irq_sem; - struct work_struct tx_timeout_task; struct work_struct watchdog_task; + struct work_struct reset_task; uint8_t fc_autoneg; struct timer_list blink_timer; @@ -328,7 +328,7 @@ struct e1000_adapter { struct e1000_rx_ring test_rx_ring; - u32 *config_space; + uint32_t *config_space; int msg_enable; #ifdef CONFIG_PCI_MSI boolean_t have_msi; diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 0d6a16c5f8c..44d39f1d829 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -67,7 +67,6 @@ static const struct e1000_stats e1000_gstrings_stats[] = { { "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) }, { "rx_crc_errors", E1000_STAT(net_stats.rx_crc_errors) }, { "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) }, - { "rx_fifo_errors", E1000_STAT(net_stats.rx_fifo_errors) }, { "rx_no_buffer_count", E1000_STAT(stats.rnbc) }, { "rx_missed_errors", E1000_STAT(net_stats.rx_missed_errors) }, { "tx_aborted_errors", E1000_STAT(net_stats.tx_aborted_errors) }, @@ -1253,6 +1252,10 @@ e1000_integrated_phy_loopback(struct e1000_adapter *adapter) e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x9140); /* autoneg off */ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x8140); + } else if (adapter->hw.phy_type == e1000_phy_gg82563) { + e1000_write_phy_reg(&adapter->hw, + GG82563_PHY_KMRN_MODE_CTRL, + 0x1CE); } /* force 1000, set loopback */ e1000_write_phy_reg(&adapter->hw, PHY_CTRL, 0x4140); @@ -1403,6 +1406,11 @@ e1000_loopback_cleanup(struct e1000_adapter *adapter) case e1000_82546_rev_3: default: hw->autoneg = TRUE; + if (hw->phy_type == e1000_phy_gg82563) { + e1000_write_phy_reg(hw, + GG82563_PHY_KMRN_MODE_CTRL, + 0x180); + } e1000_read_phy_reg(hw, PHY_CTRL, &phy_reg); if (phy_reg & MII_CR_LOOPBACK) { phy_reg &= ~MII_CR_LOOPBACK; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 3acbffd5bde..431b03ee077 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -245,7 +245,7 @@ void e1000_set_ethtool_ops(struct net_device *netdev); static void e1000_enter_82542_rst(struct e1000_adapter *adapter); static void e1000_leave_82542_rst(struct e1000_adapter *adapter); static void e1000_tx_timeout(struct net_device *dev); -static void e1000_tx_timeout_task(struct net_device *dev); +static void e1000_reset_task(struct net_device *dev); static void e1000_smartspeed(struct e1000_adapter *adapter); static inline int e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb); @@ -611,7 +611,10 @@ e1000_reset(struct e1000_adapter *adapter) adapter->hw.fc_high_water = fc_high_water_mark; adapter->hw.fc_low_water = fc_high_water_mark - 8; - adapter->hw.fc_pause_time = E1000_FC_PAUSE_TIME; + if (adapter->hw.mac_type == e1000_80003es2lan) + adapter->hw.fc_pause_time = 0xFFFF; + else + adapter->hw.fc_pause_time = E1000_FC_PAUSE_TIME; adapter->hw.fc_send_xon = 1; adapter->hw.fc = adapter->hw.original_fc; @@ -828,8 +831,8 @@ e1000_probe(struct pci_dev *pdev, adapter->phy_info_timer.function = &e1000_update_phy_info; adapter->phy_info_timer.data = (unsigned long) adapter; - INIT_WORK(&adapter->tx_timeout_task, - (void (*)(void *))e1000_tx_timeout_task, netdev); + INIT_WORK(&adapter->reset_task, + (void (*)(void *))e1000_reset_task, netdev); /* we're going to reset, so assume we have no link for now */ @@ -1390,6 +1393,10 @@ e1000_configure_tx(struct e1000_adapter *adapter) ipgr1 = DEFAULT_82542_TIPG_IPGR1; ipgr2 = DEFAULT_82542_TIPG_IPGR2; break; + case e1000_80003es2lan: + ipgr1 = DEFAULT_82543_TIPG_IPGR1; + ipgr2 = DEFAULT_80003ES2LAN_TIPG_IPGR2; + break; default: ipgr1 = DEFAULT_82543_TIPG_IPGR1; ipgr2 = DEFAULT_82543_TIPG_IPGR2; @@ -1429,6 +1436,15 @@ e1000_configure_tx(struct e1000_adapter *adapter) else tarc |= (1 << 28); E1000_WRITE_REG(hw, TARC1, tarc); + } else if (hw->mac_type == e1000_80003es2lan) { + tarc = E1000_READ_REG(hw, TARC0); + tarc |= 1; + if (hw->media_type == e1000_media_type_internal_serdes) + tarc |= (1 << 20); + E1000_WRITE_REG(hw, TARC0, tarc); + tarc = E1000_READ_REG(hw, TARC1); + tarc |= 1; + E1000_WRITE_REG(hw, TARC1, tarc); } e1000_config_collision_dist(hw); @@ -2349,6 +2365,16 @@ e1000_watchdog_task(struct e1000_adapter *adapter) netif_carrier_off(netdev); netif_stop_queue(netdev); mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); + + /* 80003ES2LAN workaround-- + * For packet buffer work-around on link down event; + * disable receives in the ISR and + * reset device here in the watchdog + */ + if (adapter->hw.mac_type == e1000_80003es2lan) { + /* reset device */ + schedule_work(&adapter->reset_task); + } } e1000_smartspeed(adapter); @@ -2374,7 +2400,8 @@ e1000_watchdog_task(struct e1000_adapter *adapter) * but we've got queued Tx work that's never going * to get done, so reset controller to flush Tx. * (Do the reset outside of interrupt context). */ - schedule_work(&adapter->tx_timeout_task); + adapter->tx_timeout_count++; + schedule_work(&adapter->reset_task); } } @@ -2940,15 +2967,15 @@ e1000_tx_timeout(struct net_device *netdev) struct e1000_adapter *adapter = netdev_priv(netdev); /* Do the reset outside of interrupt context */ - schedule_work(&adapter->tx_timeout_task); + adapter->tx_timeout_count++; + schedule_work(&adapter->reset_task); } static void -e1000_tx_timeout_task(struct net_device *netdev) +e1000_reset_task(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); - adapter->tx_timeout_count++; e1000_down(adapter); e1000_up(adapter); } @@ -3016,6 +3043,7 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu) /* fall through to get support */ case e1000_82571: case e1000_82572: + case e1000_80003es2lan: #define MAX_STD_JUMBO_FRAME_SIZE 9234 if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) { DPRINTK(PROBE, ERR, "MTU > 9216 not supported.\n"); @@ -3169,11 +3197,15 @@ e1000_update_stats(struct e1000_adapter *adapter) /* Rx Errors */ + /* RLEC on some newer hardware can be incorrect so build + * our own version based on RUC and ROC */ adapter->net_stats.rx_errors = adapter->stats.rxerrc + adapter->stats.crcerrs + adapter->stats.algnerrc + - adapter->stats.rlec + adapter->stats.cexterr; + adapter->stats.ruc + adapter->stats.roc + + adapter->stats.cexterr; adapter->net_stats.rx_dropped = 0; - adapter->net_stats.rx_length_errors = adapter->stats.rlec; + adapter->net_stats.rx_length_errors = adapter->stats.ruc + + adapter->stats.roc; adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs; adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc; adapter->net_stats.rx_missed_errors = adapter->stats.mpc; @@ -3219,7 +3251,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) struct net_device *netdev = data; struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - uint32_t icr = E1000_READ_REG(hw, ICR); + uint32_t rctl, icr = E1000_READ_REG(hw, ICR); #ifndef CONFIG_E1000_NAPI int i; #else @@ -3241,6 +3273,17 @@ e1000_intr(int irq, void *data, struct pt_regs *regs) if (unlikely(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC))) { hw->get_link_status = 1; + /* 80003ES2LAN workaround-- + * For packet buffer work-around on link down event; + * disable receives here in the ISR and + * reset adapter in watchdog + */ + if (netif_carrier_ok(netdev) && + (adapter->hw.mac_type == e1000_80003es2lan)) { + /* disable receives */ + rctl = E1000_READ_REG(hw, RCTL); + E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN); + } mod_timer(&adapter->watchdog_timer, jiffies); } -- cgit v1.2.3 From dc7c6add3493cdc71475a006b7afc3732e55abd8 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:21:40 -0800 Subject: e1000: Add copybreak when using packet split Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_main.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 431b03ee077..d641fbc7a6e 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3757,6 +3757,35 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, /* Good Receive */ skb_put(skb, length); + { + /* this looks ugly, but it seems compiler issues make it + more efficient than reusing j */ + int l1 = le16_to_cpu(rx_desc->wb.upper.length[0]); + + /* page alloc/put takes too long and effects small packet + * throughput, so unsplit small packets and save the alloc/put*/ + if (l1 && ((length + l1) < E1000_CB_LENGTH)) { + u8 *vaddr; + /* there is no documentation about how to call + * kmap_atomic, so we can't hold the mapping + * very long */ + pci_dma_sync_single_for_cpu(pdev, + ps_page_dma->ps_page_dma[0], + PAGE_SIZE, + PCI_DMA_FROMDEVICE); + vaddr = kmap_atomic(ps_page->ps_page[0], + KM_SKB_DATA_SOFTIRQ); + memcpy(skb->tail, vaddr, l1); + kunmap_atomic(vaddr, KM_SKB_DATA_SOFTIRQ); + pci_dma_sync_single_for_device(pdev, + ps_page_dma->ps_page_dma[0], + PAGE_SIZE, PCI_DMA_FROMDEVICE); + skb_put(skb, l1); + length += l1; + goto copydone; + } /* if */ + } + for (j = 0; j < adapter->rx_ps_pages; j++) { if (!(length = le16_to_cpu(rx_desc->wb.upper.length[j]))) break; @@ -3771,6 +3800,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, skb->data_len += length; } +copydone: e1000_rx_checksum(adapter, staterr, rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); skb->protocol = eth_type_trans(skb, netdev); -- cgit v1.2.3 From 30320be88fb9cae888eacf1f1eaae95a03720128 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:21:57 -0800 Subject: e1000: Added a performance enhancement - prefetch - this implementation of prefetch was tested on new and old hardware Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_main.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index d641fbc7a6e..b572a1218c8 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3569,10 +3569,15 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, skb = buffer_info->skb; buffer_info->skb = NULL; + prefetch(skb->data - NET_IP_ALIGN); + if (++i == rx_ring->count) i = 0; next_rxd = E1000_RX_DESC(*rx_ring, i); + prefetch(next_rxd); + next_buffer = &rx_ring->buffer_info[i]; next_skb = next_buffer->skb; + prefetch(next_skb->data - NET_IP_ALIGN); cleaned = TRUE; cleaned_count++; @@ -3668,6 +3673,7 @@ next_desc: cleaned_count = 0; } + /* use prefetched values */ rx_desc = next_rxd; buffer_info = next_buffer; } @@ -3710,9 +3716,9 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, i = rx_ring->next_to_clean; rx_desc = E1000_RX_DESC_PS(*rx_ring, i); staterr = le32_to_cpu(rx_desc->wb.middle.status_error); - buffer_info = &rx_ring->buffer_info[i]; while (staterr & E1000_RXD_STAT_DD) { + buffer_info = &rx_ring->buffer_info[i]; ps_page = &rx_ring->ps_page[i]; ps_page_dma = &rx_ring->ps_page_dma[i]; #ifdef CONFIG_E1000_NAPI @@ -3722,10 +3728,16 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, #endif skb = buffer_info->skb; + /* in the packet split case this is header only */ + prefetch(skb->data - NET_IP_ALIGN); + if (++i == rx_ring->count) i = 0; next_rxd = E1000_RX_DESC_PS(*rx_ring, i); + prefetch(next_rxd); + next_buffer = &rx_ring->buffer_info[i]; next_skb = next_buffer->skb; + prefetch(next_skb->data - NET_IP_ALIGN); cleaned = TRUE; cleaned_count++; @@ -3787,9 +3799,8 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, } for (j = 0; j < adapter->rx_ps_pages; j++) { - if (!(length = le16_to_cpu(rx_desc->wb.upper.length[j]))) + if (!(length= le16_to_cpu(rx_desc->wb.upper.length[j]))) break; - pci_unmap_page(pdev, ps_page_dma->ps_page_dma[j], PAGE_SIZE, PCI_DMA_FROMDEVICE); ps_page_dma->ps_page_dma[j] = 0; @@ -3837,6 +3848,7 @@ next_desc: cleaned_count = 0; } + /* use prefetched values */ rx_desc = next_rxd; buffer_info = next_buffer; -- cgit v1.2.3 From 0f15a8fae8b8558f5a9b0fec770846c487c779f6 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:46:29 -0800 Subject: e1000: Added driver comments and whitespace changes. Modified long lines of code to ensure they would not wrap beyond 80 characters. Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000.h | 10 ++-- drivers/net/e1000/e1000_hw.c | 5 +- drivers/net/e1000/e1000_hw.h | 26 +++++------ drivers/net/e1000/e1000_main.c | 101 ++++++++++++++++------------------------- 4 files changed, 60 insertions(+), 82 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index d4266f18bbd..214468c35b4 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -281,15 +281,15 @@ struct e1000_adapter { /* RX */ #ifdef CONFIG_E1000_NAPI boolean_t (*clean_rx) (struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring, - int *work_done, int work_to_do); + struct e1000_rx_ring *rx_ring, + int *work_done, int work_to_do); #else boolean_t (*clean_rx) (struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring); + struct e1000_rx_ring *rx_ring); #endif void (*alloc_rx_buf) (struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring, - int cleaned_count); + struct e1000_rx_ring *rx_ring, + int cleaned_count); struct e1000_rx_ring *rx_ring; /* One per active queue */ #ifdef CONFIG_E1000_NAPI struct net_device *polling_netdev; /* One per active queue */ diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 63e237084a5..523c2c9fc0a 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -3498,7 +3498,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw) * bit. Then, take it out of reset. * For pre-e1000_82571 hardware, we delay for 10ms between the assert * and deassert. For e1000_82571 hardware and later, we instead delay - * for 10ms after the deassertion. + * for 50us between and 10ms after the deassertion. */ ctrl = E1000_READ_REG(hw, CTRL); E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST); @@ -3920,7 +3920,8 @@ e1000_validate_mdi_setting(struct e1000_hw *hw) /****************************************************************************** * Sets up eeprom variables in the hw struct. Must be called after mac_type - * is configured. + * is configured. Additionally, if this is ICH8, the flash controller GbE + * registers must be mapped, or this will crash. * * hw - Struct containing variables accessed by shared code *****************************************************************************/ diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h index 947a156bd70..150e45e30f8 100644 --- a/drivers/net/e1000/e1000_hw.h +++ b/drivers/net/e1000/e1000_hw.h @@ -2067,19 +2067,19 @@ struct e1000_host_command_info { /* PCI-Ex registers */ /* PCI-Ex Control Register */ -#define E1000_GCR_RXD_NO_SNOOP 0x00000001 -#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 -#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004 -#define E1000_GCR_TXD_NO_SNOOP 0x00000008 -#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010 -#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020 - -#define PCI_EX_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \ - E1000_GCR_RXDSCW_NO_SNOOP | \ - E1000_GCR_RXDSCR_NO_SNOOP | \ - E1000_GCR TXD_NO_SNOOP | \ - E1000_GCR_TXDSCW_NO_SNOOP | \ - E1000_GCR_TXDSCR_NO_SNOOP) +#define E1000_GCR_RXD_NO_SNOOP 0x00000001 +#define E1000_GCR_RXDSCW_NO_SNOOP 0x00000002 +#define E1000_GCR_RXDSCR_NO_SNOOP 0x00000004 +#define E1000_GCR_TXD_NO_SNOOP 0x00000008 +#define E1000_GCR_TXDSCW_NO_SNOOP 0x00000010 +#define E1000_GCR_TXDSCR_NO_SNOOP 0x00000020 + +#define PCI_EX_NO_SNOOP_ALL (E1000_GCR_RXD_NO_SNOOP | \ + E1000_GCR_RXDSCW_NO_SNOOP | \ + E1000_GCR_RXDSCR_NO_SNOOP | \ + E1000_GCR_TXD_NO_SNOOP | \ + E1000_GCR_TXDSCW_NO_SNOOP | \ + E1000_GCR_TXDSCR_NO_SNOOP) #define E1000_GCR_L1_ACT_WITHOUT_L0S_RX 0x08000000 /* Function Active and Power State to MNG */ diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index b572a1218c8..9adaf5fa9d4 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -29,6 +29,23 @@ #include "e1000.h" /* Change Log + * 7.0.33 3-Feb-2006 + * o Added another fix for the pass false carrier bit + * 7.0.32 24-Jan-2006 + * o Need to rebuild with noew version number for the pass false carrier + * fix in e1000_hw.c + * 7.0.30 18-Jan-2006 + * o fixup for tso workaround to disable it for pci-x + * o fix mem leak on 82542 + * o fixes for 10 Mb/s connections and incorrect stats + * 7.0.28 01/06/2006 + * o hardware workaround to only set "speed mode" bit for 1G link. + * 7.0.26 12/23/2005 + * o wake on lan support modified for device ID 10B5 + * o fix dhcp + vlan issue not making it to the iAMT firmware + * 7.0.24 12/9/2005 + * o New hardware support for the Gigabit NIC embedded in the south bridge + * o Fixes to the recycling logic (skb->tail) from IBM LTC * 6.3.9 12/16/2005 * o incorporate fix for recycled skbs from IBM LTC * 6.3.7 11/18/2005 @@ -46,54 +63,8 @@ * rx_buffer_len * 6.3.1 9/19/05 * o Use adapter->tx_timeout_factor in Tx Hung Detect logic - (e1000_clean_tx_irq) + * (e1000_clean_tx_irq) * o Support for 8086:10B5 device (Quad Port) - * 6.2.14 9/15/05 - * o In AMT enabled configurations, set/reset DRV_LOAD bit on interface - * open/close - * 6.2.13 9/14/05 - * o Invoke e1000_check_mng_mode only for 8257x controllers since it - * accesses the FWSM that is not supported in other controllers - * 6.2.12 9/9/05 - * o Add support for device id E1000_DEV_ID_82546GB_QUAD_COPPER - * o set RCTL:SECRC only for controllers newer than 82543. - * o When the n/w interface comes down reset DRV_LOAD bit to notify f/w. - * This code was moved from e1000_remove to e1000_close - * 6.2.10 9/6/05 - * o Fix error in updating RDT in el1000_alloc_rx_buffers[_ps] -- one off. - * o Enable fc by default on 82573 controllers (do not read eeprom) - * o Fix rx_errors statistic not to include missed_packet_count - * o Fix rx_dropped statistic not to include missed_packet_count - (Padraig Brady) - * 6.2.9 8/30/05 - * o Remove call to update statistics from the controller ib e1000_get_stats - * 6.2.8 8/30/05 - * o Improved algorithm for rx buffer allocation/rdt update - * o Flow control watermarks relative to rx PBA size - * o Simplified 'Tx Hung' detect logic - * 6.2.7 8/17/05 - * o Report rx buffer allocation failures and tx timeout counts in stats - * 6.2.6 8/16/05 - * o Implement workaround for controller erratum -- linear non-tso packet - * following a TSO gets written back prematurely - * 6.2.5 8/15/05 - * o Set netdev->tx_queue_len based on link speed/duplex settings. - * o Fix net_stats.rx_fifo_errors - * o Do not power off PHY if SoL/IDER session is active - * 6.2.4 8/10/05 - * o Fix loopback test setup/cleanup for 82571/3 controllers - * o Fix parsing of outgoing packets (e1000_transfer_dhcp_info) to treat - * all packets as raw - * o Prevent operations that will cause the PHY to be reset if SoL/IDER - * sessions are active and log a message - * 6.2.2 7/21/05 - * o used fixed size descriptors for all MTU sizes, reduces memory load - * 6.1.2 4/13/05 - * o Fixed ethtool diagnostics - * o Enabled flow control to take default eeprom settings - * o Added stats_lock around e1000_read_phy_reg commands to avoid concurrent - * calls, one from mii_ioctl and other from within update_stats while - * processing MIIREG ioctl. */ char e1000_driver_name[] = "e1000"; @@ -178,13 +149,13 @@ int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); void e1000_free_all_tx_resources(struct e1000_adapter *adapter); void e1000_free_all_rx_resources(struct e1000_adapter *adapter); static int e1000_setup_tx_resources(struct e1000_adapter *adapter, - struct e1000_tx_ring *txdr); + struct e1000_tx_ring *txdr); static int e1000_setup_rx_resources(struct e1000_adapter *adapter, - struct e1000_rx_ring *rxdr); + struct e1000_rx_ring *rxdr); static void e1000_free_tx_resources(struct e1000_adapter *adapter, - struct e1000_tx_ring *tx_ring); + struct e1000_tx_ring *tx_ring); static void e1000_free_rx_resources(struct e1000_adapter *adapter, - struct e1000_rx_ring *rx_ring); + struct e1000_rx_ring *rx_ring); void e1000_update_stats(struct e1000_adapter *adapter); /* Local Function Prototypes */ @@ -1727,6 +1698,7 @@ e1000_configure_rx(struct e1000_adapter *adapter) uint32_t rdlen, rctl, rxcsum, ctrl_ext; if (adapter->rx_ps_pages) { + /* this is a 32 byte descriptor */ rdlen = adapter->rx_ring[0].count * sizeof(union e1000_rx_desc_packet_split); adapter->clean_rx = e1000_clean_rx_irq_ps; @@ -2576,9 +2548,9 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring, /* Workaround for Controller erratum -- * descriptor for non-tso packet in a linear SKB that follows a * tso gets written back prematurely before the data is fully - * DMAd to the controller */ + * DMA'd to the controller */ if (!skb->data_len && tx_ring->last_tx_tso && - !skb_shinfo(skb)->tso_size) { + !skb_shinfo(skb)->tso_size) { tx_ring->last_tx_tso = 0; size -= 4; } @@ -2866,7 +2838,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) #ifdef NETIF_F_TSO /* Controller Erratum workaround */ if (!skb->data_len && tx_ring->last_tx_tso && - !skb_shinfo(skb)->tso_size) + !skb_shinfo(skb)->tso_size) count++; #endif @@ -2889,7 +2861,9 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (adapter->pcix_82544) count += nr_frags; - if (adapter->hw.tx_pkt_filtering && (adapter->hw.mac_type == e1000_82573) ) + + if (adapter->hw.tx_pkt_filtering && + (adapter->hw.mac_type == e1000_82573)) e1000_transfer_dhcp_info(adapter, skb); local_irq_save(flags); @@ -3892,7 +3866,6 @@ e1000_alloc_rx_buffers(struct e1000_adapter *adapter, goto map_skb; } - if (unlikely(!skb)) { /* Better luck next round */ adapter->alloc_rx_buff_failed++; @@ -4445,8 +4418,8 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx) } #ifdef CONFIG_PM -/* these functions save and restore 16 or 64 dwords (64-256 bytes) of config - * space versus the 64 bytes that pci_[save|restore]_state handle +/* Save/restore 16 or 64 dwords of PCI config space depending on which + * bus we're on (PCI(X) vs. PCI-E) */ #define PCIE_CONFIG_SPACE_LEN 256 #define PCI_CONFIG_SPACE_LEN 64 @@ -4456,6 +4429,7 @@ e1000_pci_save_state(struct e1000_adapter *adapter) struct pci_dev *dev = adapter->pdev; int size; int i; + if (adapter->hw.mac_type >= e1000_82571) size = PCIE_CONFIG_SPACE_LEN; else @@ -4479,8 +4453,10 @@ e1000_pci_restore_state(struct e1000_adapter *adapter) struct pci_dev *dev = adapter->pdev; int size; int i; + if (adapter->config_space == NULL) return; + if (adapter->hw.mac_type >= e1000_82571) size = PCIE_CONFIG_SPACE_LEN; else @@ -4508,8 +4484,8 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) e1000_down(adapter); #ifdef CONFIG_PM - /* implement our own version of pci_save_state(pdev) because pci - * express adapters have larger 256 byte config spaces */ + /* Implement our own version of pci_save_state(pdev) because pci- + * express adapters have 256-byte config spaces. */ retval = e1000_pci_save_state(adapter); if (retval) return retval; @@ -4566,7 +4542,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) retval = pci_enable_wake(pdev, PCI_D3hot, 0); if (retval) DPRINTK(PROBE, ERR, "Error enabling D3 wake\n"); - retval = pci_enable_wake(pdev, PCI_D3cold, 0); /* 4 == D3 cold */ + retval = pci_enable_wake(pdev, PCI_D3cold, 0); if (retval) DPRINTK(PROBE, ERR, "Error enabling D3 cold wake\n"); } @@ -4582,7 +4558,8 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state) DPRINTK(PROBE, ERR, "Error enabling D3 wake\n"); retval = pci_enable_wake(pdev, PCI_D3cold, 1); if (retval) - DPRINTK(PROBE, ERR, "Error enabling D3 cold wake\n"); + DPRINTK(PROBE, ERR, + "Error enabling D3 cold wake\n"); } } -- cgit v1.2.3 From d5f9558a7778d3f7dc3c9e0d5cbe7318710532f8 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 3 Mar 2006 09:58:29 -0700 Subject: [PATCH] mv643xx_eth: Remove duplicate includes of linux/in.h and linux/ip.h Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 6b4fff80ae5..4f36489e7cd 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -37,8 +37,6 @@ #include #include #include -#include -#include #include #include -- cgit v1.2.3 From e38fd1a055cf4038c423bd841859b01aeb07d1b0 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 3 Mar 2006 09:59:28 -0700 Subject: [PATCH] mv643xx_eth: Fix misplaced parenthesis in mv643xx_eth_port_disable_rx This bug could result in a system hang. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 4f36489e7cd..4cbf84052b0 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -2496,8 +2496,8 @@ static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num) u32 channels; /* Stop Rx port activity. Check port Rx activity. */ - channels = mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num) - & 0xFF); + channels = mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num)) + & 0xFF; if (channels) { /* Issue stop command for active channels only */ mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), -- cgit v1.2.3 From 12a87c644ab1862232d0916656ff2ee42f3fb873 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 3 Mar 2006 10:00:22 -0700 Subject: [PATCH] mv643xx_eth: Rename "channels" to "queues" Use better terminology for HW queues. No functional changes. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 4cbf84052b0..098f3a28837 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -83,9 +83,9 @@ static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *MacAddr); static void eth_port_set_multicast_list(struct net_device *); static void mv643xx_eth_port_enable_tx(unsigned int port_num, - unsigned int channels); + unsigned int queues); static void mv643xx_eth_port_enable_rx(unsigned int port_num, - unsigned int channels); + unsigned int queues); static unsigned int mv643xx_eth_port_disable_tx(unsigned int port_num); static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num); static int mv643xx_eth_open(struct net_device *); @@ -466,7 +466,7 @@ static void mv643xx_eth_update_pscr(struct net_device *dev, struct mv643xx_private *mp = netdev_priv(dev); int port_num = mp->port_num; u32 o_pscr, n_pscr; - unsigned int channels; + unsigned int queues; o_pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); n_pscr = o_pscr; @@ -494,7 +494,7 @@ static void mv643xx_eth_update_pscr(struct net_device *dev, mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), n_pscr); else { - channels = mv643xx_eth_port_disable_tx(port_num); + queues = mv643xx_eth_port_disable_tx(port_num); o_pscr &= ~MV643XX_ETH_SERIAL_PORT_ENABLE; mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), @@ -503,8 +503,8 @@ static void mv643xx_eth_update_pscr(struct net_device *dev, n_pscr); mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), n_pscr); - if (channels) - mv643xx_eth_port_enable_tx(port_num, channels); + if (queues) + mv643xx_eth_port_enable_tx(port_num, queues); } } } @@ -2453,28 +2453,28 @@ static void ethernet_phy_reset(unsigned int eth_port_num) } static void mv643xx_eth_port_enable_tx(unsigned int port_num, - unsigned int channels) + unsigned int queues) { - mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), channels); + mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), queues); } static void mv643xx_eth_port_enable_rx(unsigned int port_num, - unsigned int channels) + unsigned int queues) { - mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), channels); + mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), queues); } static unsigned int mv643xx_eth_port_disable_tx(unsigned int port_num) { - u32 channels; + u32 queues; /* Stop Tx port activity. Check port Tx activity. */ - channels = mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num)) + queues = mv_read(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num)) & 0xFF; - if (channels) { - /* Issue stop command for active channels only */ + if (queues) { + /* Issue stop command for active queues only */ mv_write(MV643XX_ETH_TRANSMIT_QUEUE_COMMAND_REG(port_num), - (channels << 8)); + (queues << 8)); /* Wait for all Tx activity to terminate. */ /* Check port cause register that all Tx queues are stopped */ @@ -2488,20 +2488,20 @@ static unsigned int mv643xx_eth_port_disable_tx(unsigned int port_num) udelay(PHY_WAIT_MICRO_SECONDS); } - return channels; + return queues; } static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num) { - u32 channels; + u32 queues; /* Stop Rx port activity. Check port Rx activity. */ - channels = mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num)) + queues = mv_read(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num)) & 0xFF; - if (channels) { - /* Issue stop command for active channels only */ + if (queues) { + /* Issue stop command for active queues only */ mv_write(MV643XX_ETH_RECEIVE_QUEUE_COMMAND_REG(port_num), - (channels << 8)); + (queues << 8)); /* Wait for all Rx activity to terminate. */ /* Check port cause register that all Rx queues are stopped */ @@ -2510,7 +2510,7 @@ static unsigned int mv643xx_eth_port_disable_rx(unsigned int port_num) udelay(PHY_WAIT_MICRO_SECONDS); } - return channels; + return queues; } /* -- cgit v1.2.3 From cd6478c8aed9b2001dfff067fa66b7492a0a2ffa Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 3 Mar 2006 10:01:08 -0700 Subject: [PATCH] mv643xx_eth: Select CONFIG_MII on CONFIG_MV643XX_ETH >From : Dale Farnsworth Recent patches for the mv643xx_eth driver now use the MII interface library. Select MII so it gets built when that driver is selected. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 840bfed312f..11ca9f03b43 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2194,6 +2194,7 @@ config GFAR_NAPI config MV643XX_ETH tristate "MV-643XX Ethernet support" depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || PPC_MULTIPLATFORM + select MII help This driver supports the gigabit Ethernet on the Marvell MV643XX chipset which is used in the Momenco Ocelot C and Jaguar ATX and -- cgit v1.2.3 From c8aaea25e0b069e9572caa74f984e109899c1765 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 3 Mar 2006 10:02:05 -0700 Subject: [PATCH] mv643xx_eth: Refactor tx command queuing code Simplify and remove redundant code for filling transmit descriptors. No changes in features; it's just a code reorganization/cleanup. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 549 +++++++++++++--------------------------------- drivers/net/mv643xx_eth.h | 19 +- 2 files changed, 158 insertions(+), 410 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 098f3a28837..260be8048d3 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -10,7 +10,7 @@ * * Copyright (C) 2003 Ralf Baechle * - * Copyright (C) 2004-2005 MontaVista Software, Inc. + * Copyright (C) 2004-2006 MontaVista Software, Inc. * Dale Farnsworth * * Copyright (C) 2004 Steven J. Hill @@ -554,7 +554,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, /* UDP change : We may need this */ if ((eth_int_cause_ext & 0x0000ffff) && (mv643xx_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) && - (mp->tx_ring_size > mp->tx_desc_count + MAX_DESCS_PER_SKB)) + (mp->tx_ring_size - mp->tx_desc_count > MAX_DESCS_PER_SKB)) netif_wake_queue(dev); #ifdef MV643XX_NAPI } else { @@ -598,7 +598,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, mv643xx_eth_update_pscr(dev, &cmd); if (!netif_carrier_ok(dev)) { netif_carrier_on(dev); - if (mp->tx_ring_size > mp->tx_desc_count + + if (mp->tx_ring_size - mp->tx_desc_count > MAX_DESCS_PER_SKB) { netif_wake_queue(dev); /* Start TX queue */ @@ -777,9 +777,6 @@ static void ether_init_tx_desc_ring(struct mv643xx_private *mp) mp->tx_curr_desc_q = 0; mp->tx_used_desc_q = 0; -#ifdef MV643XX_CHECKSUM_OFFLOAD_TX - mp->tx_first_desc_q = 0; -#endif mp->tx_desc_area_size = tx_desc_num * sizeof(struct eth_tx_desc); @@ -1085,8 +1082,7 @@ static void mv643xx_tx(struct net_device *dev) } if (netif_queue_stopped(dev) && - mp->tx_ring_size > - mp->tx_desc_count + MAX_DESCS_PER_SKB) + mp->tx_ring_size - mp->tx_desc_count > MAX_DESCS_PER_SKB) netif_wake_queue(dev); } @@ -1133,7 +1129,10 @@ static int mv643xx_poll(struct net_device *dev, int *budget) } #endif -/* Hardware can't handle unaligned fragments smaller than 9 bytes. +/** + * has_tiny_unaligned_frags - check if skb has any small, unaligned fragments + * + * Hardware can't handle unaligned fragments smaller than 9 bytes. * This helper function detects that case. */ @@ -1150,223 +1149,170 @@ static inline unsigned int has_tiny_unaligned_frags(struct sk_buff *skb) return 0; } +/** + * eth_alloc_tx_desc_index - return the index of the next available tx desc + */ +static int eth_alloc_tx_desc_index(struct mv643xx_private *mp) +{ + int tx_desc_curr; + + tx_desc_curr = mp->tx_curr_desc_q; -/* - * mv643xx_eth_start_xmit - * - * This function is queues a packet in the Tx descriptor for - * required port. - * - * Input : skb - a pointer to socket buffer - * dev - a pointer to the required port + BUG_ON(mp->tx_desc_count >= mp->tx_ring_size); + mp->tx_desc_count++; + + mp->tx_curr_desc_q = (tx_desc_curr + 1) % mp->tx_ring_size; + + BUG_ON(mp->tx_curr_desc_q == mp->tx_used_desc_q); + + return tx_desc_curr; +} + +/** + * eth_tx_fill_frag_descs - fill tx hw descriptors for an skb's fragments. * - * Output : zero upon success + * Ensure the data for each fragment to be transmitted is mapped properly, + * then fill in descriptors in the tx hw queue. */ -static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) +static void eth_tx_fill_frag_descs(struct mv643xx_private *mp, + struct sk_buff *skb) { - struct mv643xx_private *mp = netdev_priv(dev); + int frag; + int tx_index; + struct eth_tx_desc *desc; struct net_device_stats *stats = &mp->stats; - ETH_FUNC_RET_STATUS status; - unsigned long flags; - struct pkt_info pkt_info; - if (netif_queue_stopped(dev)) { - printk(KERN_ERR - "%s: Tried sending packet when interface is stopped\n", - dev->name); - return 1; + for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { + skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; + + tx_index = eth_alloc_tx_desc_index(mp); + desc = &mp->p_tx_desc_area[tx_index]; + + desc->cmd_sts = ETH_BUFFER_OWNED_BY_DMA; + /* Last Frag enables interrupt and frees the skb */ + if (frag == (skb_shinfo(skb)->nr_frags - 1)) { + desc->cmd_sts |= ETH_ZERO_PADDING | + ETH_TX_LAST_DESC | + ETH_TX_ENABLE_INTERRUPT; + mp->tx_skb[tx_index] = skb; + } else + mp->tx_skb[tx_index] = 0; + + desc = &mp->p_tx_desc_area[tx_index]; + desc->l4i_chk = 0; + desc->byte_cnt = this_frag->size; + desc->buf_ptr = dma_map_page(NULL, this_frag->page, + this_frag->page_offset, + this_frag->size, + DMA_TO_DEVICE); + stats->tx_bytes += this_frag->size; } +} - /* This is a hard error, log it. */ - if ((mp->tx_ring_size - mp->tx_desc_count) <= - (skb_shinfo(skb)->nr_frags + 1)) { - netif_stop_queue(dev); - printk(KERN_ERR - "%s: Bug in mv643xx_eth - Trying to transmit when" - " queue full !\n", dev->name); - return 1; - } +/** + * eth_tx_submit_descs_for_skb - submit data from an skb to the tx hw + * + * Ensure the data for an skb to be transmitted is mapped properly, + * then fill in descriptors in the tx hw queue and start the hardware. + */ +static int eth_tx_submit_descs_for_skb(struct mv643xx_private *mp, + struct sk_buff *skb) +{ + int tx_index; + struct eth_tx_desc *desc; + u32 cmd_sts; + int length; + int tx_bytes = 0; - /* Paranoid check - this shouldn't happen */ - if (skb == NULL) { - stats->tx_dropped++; - printk(KERN_ERR "mv64320_eth paranoid check failed\n"); - return 1; - } + cmd_sts = ETH_TX_FIRST_DESC | ETH_GEN_CRC | ETH_BUFFER_OWNED_BY_DMA; -#ifdef MV643XX_CHECKSUM_OFFLOAD_TX - if (has_tiny_unaligned_frags(skb)) { - if ((skb_linearize(skb, GFP_ATOMIC) != 0)) { - stats->tx_dropped++; - printk(KERN_DEBUG "%s: failed to linearize tiny " - "unaligned fragment\n", dev->name); - return 1; - } + tx_index = eth_alloc_tx_desc_index(mp); + desc = &mp->p_tx_desc_area[tx_index]; + + if (skb_shinfo(skb)->nr_frags) { + eth_tx_fill_frag_descs(mp, skb); + + length = skb_headlen(skb); + mp->tx_skb[tx_index] = 0; + } else { + cmd_sts |= ETH_ZERO_PADDING | + ETH_TX_LAST_DESC | + ETH_TX_ENABLE_INTERRUPT; + length = skb->len; + mp->tx_skb[tx_index] = skb; } - spin_lock_irqsave(&mp->lock, flags); + desc->byte_cnt = length; + desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); + tx_bytes += length; - if (!skb_shinfo(skb)->nr_frags) { - if (skb->ip_summed != CHECKSUM_HW) { - /* Errata BTS #50, IHL must be 5 if no HW checksum */ - pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | - ETH_TX_FIRST_DESC | - ETH_TX_LAST_DESC | - 5 << ETH_TX_IHL_SHIFT; - pkt_info.l4i_chk = 0; - } else { - pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | - ETH_TX_FIRST_DESC | - ETH_TX_LAST_DESC | - ETH_GEN_TCP_UDP_CHECKSUM | - ETH_GEN_IP_V_4_CHECKSUM | - skb->nh.iph->ihl << ETH_TX_IHL_SHIFT; - /* CPU already calculated pseudo header checksum. */ - if ((skb->protocol == ETH_P_IP) && - (skb->nh.iph->protocol == IPPROTO_UDP) ) { - pkt_info.cmd_sts |= ETH_UDP_FRAME; - pkt_info.l4i_chk = skb->h.uh->check; - } else if ((skb->protocol == ETH_P_IP) && - (skb->nh.iph->protocol == IPPROTO_TCP)) - pkt_info.l4i_chk = skb->h.th->check; - else { - printk(KERN_ERR - "%s: chksum proto != IPv4 TCP or UDP\n", - dev->name); - spin_unlock_irqrestore(&mp->lock, flags); - return 1; - } + if (skb->ip_summed == CHECKSUM_HW) { + BUG_ON(skb->protocol != ETH_P_IP); + + cmd_sts |= ETH_GEN_TCP_UDP_CHECKSUM | + ETH_GEN_IP_V_4_CHECKSUM | + skb->nh.iph->ihl << ETH_TX_IHL_SHIFT; + + switch (skb->nh.iph->protocol) { + case IPPROTO_UDP: + cmd_sts |= ETH_UDP_FRAME; + desc->l4i_chk = skb->h.uh->check; + break; + case IPPROTO_TCP: + desc->l4i_chk = skb->h.th->check; + break; + default: + BUG(); } - pkt_info.byte_cnt = skb->len; - pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len, - DMA_TO_DEVICE); - pkt_info.return_info = skb; - status = eth_port_send(mp, &pkt_info); - if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL)) - printk(KERN_ERR "%s: Error on transmitting packet\n", - dev->name); - stats->tx_bytes += pkt_info.byte_cnt; } else { - unsigned int frag; - - /* first frag which is skb header */ - pkt_info.byte_cnt = skb_headlen(skb); - pkt_info.buf_ptr = dma_map_single(NULL, skb->data, - skb_headlen(skb), - DMA_TO_DEVICE); - pkt_info.l4i_chk = 0; - pkt_info.return_info = 0; - - if (skb->ip_summed != CHECKSUM_HW) - /* Errata BTS #50, IHL must be 5 if no HW checksum */ - pkt_info.cmd_sts = ETH_TX_FIRST_DESC | - 5 << ETH_TX_IHL_SHIFT; - else { - pkt_info.cmd_sts = ETH_TX_FIRST_DESC | - ETH_GEN_TCP_UDP_CHECKSUM | - ETH_GEN_IP_V_4_CHECKSUM | - skb->nh.iph->ihl << ETH_TX_IHL_SHIFT; - /* CPU already calculated pseudo header checksum. */ - if ((skb->protocol == ETH_P_IP) && - (skb->nh.iph->protocol == IPPROTO_UDP)) { - pkt_info.cmd_sts |= ETH_UDP_FRAME; - pkt_info.l4i_chk = skb->h.uh->check; - } else if ((skb->protocol == ETH_P_IP) && - (skb->nh.iph->protocol == IPPROTO_TCP)) - pkt_info.l4i_chk = skb->h.th->check; - else { - printk(KERN_ERR - "%s: chksum proto != IPv4 TCP or UDP\n", - dev->name); - spin_unlock_irqrestore(&mp->lock, flags); - return 1; - } - } + /* Errata BTS #50, IHL must be 5 if no HW checksum */ + cmd_sts |= 5 << ETH_TX_IHL_SHIFT; + desc->l4i_chk = 0; + } - status = eth_port_send(mp, &pkt_info); - if (status != ETH_OK) { - if ((status == ETH_ERROR)) - printk(KERN_ERR - "%s: Error on transmitting packet\n", - dev->name); - if (status == ETH_QUEUE_FULL) - printk("Error on Queue Full \n"); - if (status == ETH_QUEUE_LAST_RESOURCE) - printk("Tx resource error \n"); - } - stats->tx_bytes += pkt_info.byte_cnt; - - /* Check for the remaining frags */ - for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { - skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; - pkt_info.l4i_chk = 0x0000; - pkt_info.cmd_sts = 0x00000000; - - /* Last Frag enables interrupt and frees the skb */ - if (frag == (skb_shinfo(skb)->nr_frags - 1)) { - pkt_info.cmd_sts |= ETH_TX_ENABLE_INTERRUPT | - ETH_TX_LAST_DESC; - pkt_info.return_info = skb; - } else { - pkt_info.return_info = 0; - } - pkt_info.l4i_chk = 0; - pkt_info.byte_cnt = this_frag->size; + /* ensure all other descriptors are written before first cmd_sts */ + wmb(); + desc->cmd_sts = cmd_sts; - pkt_info.buf_ptr = dma_map_page(NULL, this_frag->page, - this_frag->page_offset, - this_frag->size, - DMA_TO_DEVICE); + /* ensure all descriptors are written before poking hardware */ + wmb(); + mv643xx_eth_port_enable_tx(mp->port_num, mp->port_tx_queue_command); - status = eth_port_send(mp, &pkt_info); + return tx_bytes; +} - if (status != ETH_OK) { - if ((status == ETH_ERROR)) - printk(KERN_ERR "%s: Error on " - "transmitting packet\n", - dev->name); +/** + * mv643xx_eth_start_xmit - queue an skb to the hardware for transmission + * + */ +static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct mv643xx_private *mp = netdev_priv(dev); + struct net_device_stats *stats = &mp->stats; + unsigned long flags; - if (status == ETH_QUEUE_LAST_RESOURCE) - printk("Tx resource error \n"); + BUG_ON(netif_queue_stopped(dev)); + BUG_ON(skb == NULL); + BUG_ON(mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB); - if (status == ETH_QUEUE_FULL) - printk("Queue is full \n"); - } - stats->tx_bytes += pkt_info.byte_cnt; + if (has_tiny_unaligned_frags(skb)) { + if ((skb_linearize(skb, GFP_ATOMIC) != 0)) { + stats->tx_dropped++; + printk(KERN_DEBUG "%s: failed to linearize tiny " + "unaligned fragment\n", dev->name); + return 1; } } -#else - spin_lock_irqsave(&mp->lock, flags); - - pkt_info.cmd_sts = ETH_TX_ENABLE_INTERRUPT | ETH_TX_FIRST_DESC | - ETH_TX_LAST_DESC; - pkt_info.l4i_chk = 0; - pkt_info.byte_cnt = skb->len; - pkt_info.buf_ptr = dma_map_single(NULL, skb->data, skb->len, - DMA_TO_DEVICE); - pkt_info.return_info = skb; - status = eth_port_send(mp, &pkt_info); - if ((status == ETH_ERROR) || (status == ETH_QUEUE_FULL)) - printk(KERN_ERR "%s: Error on transmitting packet\n", - dev->name); - stats->tx_bytes += pkt_info.byte_cnt; -#endif - /* Check if TX queue can handle another skb. If not, then - * signal higher layers to stop requesting TX - */ - if (mp->tx_ring_size <= (mp->tx_desc_count + MAX_DESCS_PER_SKB)) - /* - * Stop getting skb's from upper layers. - * Getting skb's from upper layers will be enabled again after - * packets are released. - */ - netif_stop_queue(dev); + spin_lock_irqsave(&mp->lock, flags); - /* Update statistics and start of transmittion time */ + stats->tx_bytes = eth_tx_submit_descs_for_skb(mp, skb); stats->tx_packets++; dev->trans_start = jiffies; + if (mp->tx_ring_size - mp->tx_desc_count < MAX_DESCS_PER_SKB) + netif_stop_queue(dev); + spin_unlock_irqrestore(&mp->lock, flags); return 0; /* success */ @@ -1812,22 +1758,6 @@ MODULE_DESCRIPTION("Ethernet driver for Marvell MV643XX"); * to the Rx descriptor ring to enable the reuse of this source. * Return Rx resource is done using the eth_rx_return_buff API. * - * Transmit operation: - * The eth_port_send API supports Scatter-Gather which enables to - * send a packet spanned over multiple buffers. This means that - * for each packet info structure given by the user and put into - * the Tx descriptors ring, will be transmitted only if the 'LAST' - * bit will be set in the packet info command status field. This - * API also consider restriction regarding buffer alignments and - * sizes. - * The user must return a Tx resource after ensuring the buffer - * has been transmitted to enable the Tx ring indexes to update. - * - * BOARD LAYOUT - * This device is on-board. No jumper diagram is necessary. - * - * EXTERNAL INTERFACE - * * Prior to calling the initialization routine eth_port_init() the user * must set the following fields under mv643xx_private struct: * port_num User Ethernet port number. @@ -1881,7 +1811,6 @@ static void eth_port_set_filter_table_entry(int table, unsigned char entry); static void eth_port_init(struct mv643xx_private *mp) { mp->rx_resource_err = 0; - mp->tx_resource_err = 0; eth_port_reset(mp->port_num); @@ -2672,166 +2601,6 @@ static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, eth_port_write_smi_reg(mp->port_num, location, val); } -/* - * eth_port_send - Send an Ethernet packet - * - * DESCRIPTION: - * This routine send a given packet described by p_pktinfo parameter. It - * supports transmitting of a packet spaned over multiple buffers. The - * routine updates 'curr' and 'first' indexes according to the packet - * segment passed to the routine. In case the packet segment is first, - * the 'first' index is update. In any case, the 'curr' index is updated. - * If the routine get into Tx resource error it assigns 'curr' index as - * 'first'. This way the function can abort Tx process of multiple - * descriptors per packet. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port Control srtuct. - * struct pkt_info *p_pkt_info User packet buffer. - * - * OUTPUT: - * Tx ring 'curr' and 'first' indexes are updated. - * - * RETURN: - * ETH_QUEUE_FULL in case of Tx resource error. - * ETH_ERROR in case the routine can not access Tx desc ring. - * ETH_QUEUE_LAST_RESOURCE if the routine uses the last Tx resource. - * ETH_OK otherwise. - * - */ -#ifdef MV643XX_CHECKSUM_OFFLOAD_TX -/* - * Modified to include the first descriptor pointer in case of SG - */ -static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, - struct pkt_info *p_pkt_info) -{ - int tx_desc_curr, tx_desc_used, tx_first_desc, tx_next_desc; - struct eth_tx_desc *current_descriptor; - struct eth_tx_desc *first_descriptor; - u32 command; - - /* Do not process Tx ring in case of Tx ring resource error */ - if (mp->tx_resource_err) - return ETH_QUEUE_FULL; - - /* - * The hardware requires that each buffer that is <= 8 bytes - * in length must be aligned on an 8 byte boundary. - */ - if (p_pkt_info->byte_cnt <= 8 && p_pkt_info->buf_ptr & 0x7) { - printk(KERN_ERR - "mv643xx_eth port %d: packet size <= 8 problem\n", - mp->port_num); - return ETH_ERROR; - } - - mp->tx_desc_count++; - BUG_ON(mp->tx_desc_count > mp->tx_ring_size); - - /* Get the Tx Desc ring indexes */ - tx_desc_curr = mp->tx_curr_desc_q; - tx_desc_used = mp->tx_used_desc_q; - - current_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; - - tx_next_desc = (tx_desc_curr + 1) % mp->tx_ring_size; - - current_descriptor->buf_ptr = p_pkt_info->buf_ptr; - current_descriptor->byte_cnt = p_pkt_info->byte_cnt; - current_descriptor->l4i_chk = p_pkt_info->l4i_chk; - mp->tx_skb[tx_desc_curr] = p_pkt_info->return_info; - - command = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC | - ETH_BUFFER_OWNED_BY_DMA; - if (command & ETH_TX_FIRST_DESC) { - tx_first_desc = tx_desc_curr; - mp->tx_first_desc_q = tx_first_desc; - first_descriptor = current_descriptor; - mp->tx_first_command = command; - } else { - tx_first_desc = mp->tx_first_desc_q; - first_descriptor = &mp->p_tx_desc_area[tx_first_desc]; - BUG_ON(first_descriptor == NULL); - current_descriptor->cmd_sts = command; - } - - if (command & ETH_TX_LAST_DESC) { - wmb(); - first_descriptor->cmd_sts = mp->tx_first_command; - - wmb(); - mv643xx_eth_port_enable_tx(mp->port_num, mp->port_tx_queue_command); - - /* - * Finish Tx packet. Update first desc in case of Tx resource - * error */ - tx_first_desc = tx_next_desc; - mp->tx_first_desc_q = tx_first_desc; - } - - /* Check for ring index overlap in the Tx desc ring */ - if (tx_next_desc == tx_desc_used) { - mp->tx_resource_err = 1; - mp->tx_curr_desc_q = tx_first_desc; - - return ETH_QUEUE_LAST_RESOURCE; - } - - mp->tx_curr_desc_q = tx_next_desc; - - return ETH_OK; -} -#else -static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, - struct pkt_info *p_pkt_info) -{ - int tx_desc_curr; - int tx_desc_used; - struct eth_tx_desc *current_descriptor; - unsigned int command_status; - - /* Do not process Tx ring in case of Tx ring resource error */ - if (mp->tx_resource_err) - return ETH_QUEUE_FULL; - - mp->tx_desc_count++; - BUG_ON(mp->tx_desc_count > mp->tx_ring_size); - - /* Get the Tx Desc ring indexes */ - tx_desc_curr = mp->tx_curr_desc_q; - tx_desc_used = mp->tx_used_desc_q; - current_descriptor = &mp->p_tx_desc_area[tx_desc_curr]; - - command_status = p_pkt_info->cmd_sts | ETH_ZERO_PADDING | ETH_GEN_CRC; - current_descriptor->buf_ptr = p_pkt_info->buf_ptr; - current_descriptor->byte_cnt = p_pkt_info->byte_cnt; - mp->tx_skb[tx_desc_curr] = p_pkt_info->return_info; - - /* Set last desc with DMA ownership and interrupt enable. */ - wmb(); - current_descriptor->cmd_sts = command_status | - ETH_BUFFER_OWNED_BY_DMA | ETH_TX_ENABLE_INTERRUPT; - - wmb(); - mv643xx_eth_port_enable_tx(mp->port_num, mp->port_tx_queue_command); - - /* Finish Tx packet. Update first desc in case of Tx resource error */ - tx_desc_curr = (tx_desc_curr + 1) % mp->tx_ring_size; - - /* Update the current descriptor */ - mp->tx_curr_desc_q = tx_desc_curr; - - /* Check for ring index overlap in the Tx desc ring */ - if (tx_desc_curr == tx_desc_used) { - mp->tx_resource_err = 1; - return ETH_QUEUE_LAST_RESOURCE; - } - - return ETH_OK; -} -#endif - /* * eth_tx_return_desc - Free all used Tx descriptors * @@ -2858,7 +2627,6 @@ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, struct pkt_info *p_pkt_info) { int tx_desc_used; - int tx_busy_desc; struct eth_tx_desc *p_tx_desc_used; unsigned int command_status; unsigned long flags; @@ -2866,33 +2634,23 @@ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, spin_lock_irqsave(&mp->lock, flags); -#ifdef MV643XX_CHECKSUM_OFFLOAD_TX - tx_busy_desc = mp->tx_first_desc_q; -#else - tx_busy_desc = mp->tx_curr_desc_q; -#endif + BUG_ON(mp->tx_desc_count < 0); + if (mp->tx_desc_count == 0) { + /* no more tx descs in use */ + err = ETH_ERROR; + goto out; + } /* Get the Tx Desc ring indexes */ tx_desc_used = mp->tx_used_desc_q; p_tx_desc_used = &mp->p_tx_desc_area[tx_desc_used]; - /* Sanity check */ - if (p_tx_desc_used == NULL) { - err = ETH_ERROR; - goto out; - } - - /* Stop release. About to overlap the current available Tx descriptor */ - if (tx_desc_used == tx_busy_desc && !mp->tx_resource_err) { - err = ETH_ERROR; - goto out; - } + BUG_ON(p_tx_desc_used == NULL); command_status = p_tx_desc_used->cmd_sts; - - /* Still transmitting... */ if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) { + /* Still transmitting... */ err = ETH_ERROR; goto out; } @@ -2907,9 +2665,6 @@ static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, /* Update the next descriptor to release. */ mp->tx_used_desc_q = (tx_desc_used + 1) % mp->tx_ring_size; - /* Any Tx return cancels the Tx resource error status */ - mp->tx_resource_err = 0; - BUG_ON(mp->tx_desc_count == 0); mp->tx_desc_count--; diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index a553054e8da..8768e1ba45d 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -330,7 +330,6 @@ struct mv643xx_private { u32 tx_sram_size; /* Size of tx sram area */ int rx_resource_err; /* Rx ring resource error flag */ - int tx_resource_err; /* Tx ring resource error flag */ /* Tx/Rx rings managment indexes fields. For driver use */ @@ -339,10 +338,6 @@ struct mv643xx_private { /* Next available and first returning Tx resource */ int tx_curr_desc_q, tx_used_desc_q; -#ifdef MV643XX_CHECKSUM_OFFLOAD_TX - int tx_first_desc_q; - u32 tx_first_command; -#endif #ifdef MV643XX_TX_FAST_REFILL u32 tx_clean_threshold; @@ -350,12 +345,12 @@ struct mv643xx_private { struct eth_rx_desc *p_rx_desc_area; dma_addr_t rx_desc_dma; - unsigned int rx_desc_area_size; + int rx_desc_area_size; struct sk_buff **rx_skb; struct eth_tx_desc *p_tx_desc_area; dma_addr_t tx_desc_dma; - unsigned int tx_desc_area_size; + int tx_desc_area_size; struct sk_buff **tx_skb; struct work_struct tx_timeout_task; @@ -367,13 +362,13 @@ struct mv643xx_private { struct mv643xx_mib_counters mib_counters; spinlock_t lock; /* Size of Tx Ring per queue */ - unsigned int tx_ring_size; + int tx_ring_size; /* Number of tx descriptors in use */ - unsigned int tx_desc_count; + int tx_desc_count; /* Size of Rx Ring per queue */ - unsigned int rx_ring_size; + int rx_ring_size; /* Number of rx descriptors in use */ - unsigned int rx_desc_count; + int rx_desc_count; /* * rx_task used to fill RX ring out of bottom half context @@ -416,8 +411,6 @@ static void eth_port_read_smi_reg(unsigned int eth_port_num, static void eth_clear_mib_counters(unsigned int eth_port_num); /* Port data flow control routines */ -static ETH_FUNC_RET_STATUS eth_port_send(struct mv643xx_private *mp, - struct pkt_info *p_pkt_info); static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, struct pkt_info *p_pkt_info); static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp, -- cgit v1.2.3 From ff561eef9fb37c7180085e08418acfc009a9ada7 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 3 Mar 2006 10:02:51 -0700 Subject: [PATCH] mv643xx_eth: Refactor/clean up tx queue handling Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 257 +++++++++++++++------------------------------- drivers/net/mv643xx_eth.h | 4 - 2 files changed, 84 insertions(+), 177 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 260be8048d3..8a24b39f3cc 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -62,6 +62,9 @@ #define WRAP HW_IP_ALIGN + ETH_HLEN + VLAN_HLEN + FCS_LEN #define RX_SKB_SIZE ((dev->mtu + WRAP + 7) & ~0x7) +#define ETH_RX_QUEUES_ENABLED (1 << 0) /* use only Q0 for receive */ +#define ETH_TX_QUEUES_ENABLED (1 << 0) /* use only Q0 for transmit */ + #define INT_UNMASK_ALL 0x0007ffff #define INT_UNMASK_ALL_EXT 0x0011ffff #define INT_MASK_ALL 0x00000000 @@ -333,49 +336,78 @@ static void mv643xx_eth_tx_timeout_task(struct net_device *dev) netif_device_attach(dev); } -/* - * mv643xx_eth_free_tx_queue - * - * Input : dev - a pointer to the required interface +/** + * mv643xx_eth_free_tx_descs - Free the tx desc data for completed descriptors * - * Output : 0 if was able to release skb , nonzero otherwise + * If force is non-zero, frees uncompleted descriptors as well */ -static int mv643xx_eth_free_tx_queue(struct net_device *dev, - unsigned int eth_int_cause_ext) +int mv643xx_eth_free_tx_descs(struct net_device *dev, int force) { struct mv643xx_private *mp = netdev_priv(dev); - struct net_device_stats *stats = &mp->stats; - struct pkt_info pkt_info; - int released = 1; + struct eth_tx_desc *desc; + u32 cmd_sts; + struct sk_buff *skb; + unsigned long flags; + int tx_index; + dma_addr_t addr; + int count; + int released = 0; - if (!(eth_int_cause_ext & (BIT0 | BIT8))) - return released; + while (mp->tx_desc_count > 0) { + spin_lock_irqsave(&mp->lock, flags); + tx_index = mp->tx_used_desc_q; + desc = &mp->p_tx_desc_area[tx_index]; + cmd_sts = desc->cmd_sts; + + if (!force && (cmd_sts & ETH_BUFFER_OWNED_BY_DMA)) { + spin_unlock_irqrestore(&mp->lock, flags); + return released; + } + + mp->tx_used_desc_q = (tx_index + 1) % mp->tx_ring_size; + mp->tx_desc_count--; + + addr = desc->buf_ptr; + count = desc->byte_cnt; + skb = mp->tx_skb[tx_index]; + if (skb) + mp->tx_skb[tx_index] = NULL; + + spin_unlock_irqrestore(&mp->lock, flags); - /* Check only queue 0 */ - while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) { - if (pkt_info.cmd_sts & BIT0) { + if (cmd_sts & BIT0) { printk("%s: Error in TX\n", dev->name); - stats->tx_errors++; + mp->stats.tx_errors++; } - if (pkt_info.cmd_sts & ETH_TX_FIRST_DESC) - dma_unmap_single(NULL, pkt_info.buf_ptr, - pkt_info.byte_cnt, - DMA_TO_DEVICE); + if (cmd_sts & ETH_TX_FIRST_DESC) + dma_unmap_single(NULL, addr, count, DMA_TO_DEVICE); else - dma_unmap_page(NULL, pkt_info.buf_ptr, - pkt_info.byte_cnt, - DMA_TO_DEVICE); + dma_unmap_page(NULL, addr, count, DMA_TO_DEVICE); - if (pkt_info.return_info) { - dev_kfree_skb_irq(pkt_info.return_info); - released = 0; - } + if (skb) + dev_kfree_skb_irq(skb); + + released = 1; } return released; } +static void mv643xx_eth_free_completed_tx_descs(struct net_device *dev) +{ + struct mv643xx_private *mp = netdev_priv(dev); + + if (mv643xx_eth_free_tx_descs(dev, 0) && + mp->tx_ring_size - mp->tx_desc_count >= MAX_DESCS_PER_SKB) + netif_wake_queue(dev); +} + +static void mv643xx_eth_free_all_tx_descs(struct net_device *dev) +{ + mv643xx_eth_free_tx_descs(dev, 1); +} + /* * mv643xx_eth_receive * @@ -547,15 +579,13 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, */ mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), ~eth_int_cause); - if (eth_int_cause_ext != 0x0) + if (eth_int_cause_ext != 0x0) { mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG (port_num), ~eth_int_cause_ext); - - /* UDP change : We may need this */ - if ((eth_int_cause_ext & 0x0000ffff) && - (mv643xx_eth_free_tx_queue(dev, eth_int_cause_ext) == 0) && - (mp->tx_ring_size - mp->tx_desc_count > MAX_DESCS_PER_SKB)) - netif_wake_queue(dev); + /* UDP change : We may need this */ + if (eth_int_cause_ext & (BIT0 | BIT8)) + mv643xx_eth_free_completed_tx_descs(dev); + } #ifdef MV643XX_NAPI } else { if (netif_rx_schedule_prep(dev)) { @@ -596,14 +626,13 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, if (mii_link_ok(&mp->mii)) { mii_ethtool_gset(&mp->mii, &cmd); mv643xx_eth_update_pscr(dev, &cmd); + mv643xx_eth_port_enable_tx(port_num, + ETH_TX_QUEUES_ENABLED); if (!netif_carrier_ok(dev)) { netif_carrier_on(dev); - if (mp->tx_ring_size - mp->tx_desc_count > - MAX_DESCS_PER_SKB) { + if (mp->tx_ring_size - mp->tx_desc_count >= + MAX_DESCS_PER_SKB) netif_wake_queue(dev); - /* Start TX queue */ - mv643xx_eth_port_enable_tx(port_num, mp->port_tx_queue_command); - } } } else if (netif_carrier_ok(dev)) { netif_stop_queue(dev); @@ -735,9 +764,6 @@ static void ether_init_rx_desc_ring(struct mv643xx_private *mp) mp->rx_used_desc_q = 0; mp->rx_desc_area_size = rx_desc_num * sizeof(struct eth_rx_desc); - - /* Enable queue 0 for this port */ - mp->port_rx_queue_command = 1; } /* @@ -779,9 +805,6 @@ static void ether_init_tx_desc_ring(struct mv643xx_private *mp) mp->tx_used_desc_q = 0; mp->tx_desc_area_size = tx_desc_num * sizeof(struct eth_tx_desc); - - /* Enable queue 0 for this port */ - mp->port_tx_queue_command = 1; } static int mv643xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) @@ -963,25 +986,14 @@ out_free_irq: static void mv643xx_eth_free_tx_rings(struct net_device *dev) { struct mv643xx_private *mp = netdev_priv(dev); - unsigned int port_num = mp->port_num; - unsigned int curr; - struct sk_buff *skb; /* Stop Tx Queues */ - mv643xx_eth_port_disable_tx(port_num); + mv643xx_eth_port_disable_tx(mp->port_num); - /* Free outstanding skb's on TX rings */ - for (curr = 0; mp->tx_desc_count && curr < mp->tx_ring_size; curr++) { - skb = mp->tx_skb[curr]; - if (skb) { - mp->tx_desc_count -= skb_shinfo(skb)->nr_frags; - dev_kfree_skb(skb); - mp->tx_desc_count--; - } - } - if (mp->tx_desc_count) - printk("%s: Error on Tx descriptor free - could not free %d" - " descriptors\n", dev->name, mp->tx_desc_count); + /* Free outstanding skb's on TX ring */ + mv643xx_eth_free_all_tx_descs(dev); + + BUG_ON(mp->tx_used_desc_q != mp->tx_curr_desc_q); /* Free TX ring */ if (mp->tx_sram_size) @@ -1062,30 +1074,6 @@ static int mv643xx_eth_stop(struct net_device *dev) } #ifdef MV643XX_NAPI -static void mv643xx_tx(struct net_device *dev) -{ - struct mv643xx_private *mp = netdev_priv(dev); - struct pkt_info pkt_info; - - while (eth_tx_return_desc(mp, &pkt_info) == ETH_OK) { - if (pkt_info.cmd_sts & ETH_TX_FIRST_DESC) - dma_unmap_single(NULL, pkt_info.buf_ptr, - pkt_info.byte_cnt, - DMA_TO_DEVICE); - else - dma_unmap_page(NULL, pkt_info.buf_ptr, - pkt_info.byte_cnt, - DMA_TO_DEVICE); - - if (pkt_info.return_info) - dev_kfree_skb_irq(pkt_info.return_info); - } - - if (netif_queue_stopped(dev) && - mp->tx_ring_size - mp->tx_desc_count > MAX_DESCS_PER_SKB) - netif_wake_queue(dev); -} - /* * mv643xx_poll * @@ -1099,7 +1087,7 @@ static int mv643xx_poll(struct net_device *dev, int *budget) #ifdef MV643XX_TX_FAST_REFILL if (++mp->tx_clean_threshold > 5) { - mv643xx_tx(dev); + mv643xx_eth_free_completed_tx_descs(dev); mp->tx_clean_threshold = 0; } #endif @@ -1156,11 +1144,9 @@ static int eth_alloc_tx_desc_index(struct mv643xx_private *mp) { int tx_desc_curr; - tx_desc_curr = mp->tx_curr_desc_q; - BUG_ON(mp->tx_desc_count >= mp->tx_ring_size); - mp->tx_desc_count++; + tx_desc_curr = mp->tx_curr_desc_q; mp->tx_curr_desc_q = (tx_desc_curr + 1) % mp->tx_ring_size; BUG_ON(mp->tx_curr_desc_q == mp->tx_used_desc_q); @@ -1180,7 +1166,6 @@ static void eth_tx_fill_frag_descs(struct mv643xx_private *mp, int frag; int tx_index; struct eth_tx_desc *desc; - struct net_device_stats *stats = &mp->stats; for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) { skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag]; @@ -1205,7 +1190,6 @@ static void eth_tx_fill_frag_descs(struct mv643xx_private *mp, this_frag->page_offset, this_frag->size, DMA_TO_DEVICE); - stats->tx_bytes += this_frag->size; } } @@ -1215,21 +1199,21 @@ static void eth_tx_fill_frag_descs(struct mv643xx_private *mp, * Ensure the data for an skb to be transmitted is mapped properly, * then fill in descriptors in the tx hw queue and start the hardware. */ -static int eth_tx_submit_descs_for_skb(struct mv643xx_private *mp, - struct sk_buff *skb) +static void eth_tx_submit_descs_for_skb(struct mv643xx_private *mp, + struct sk_buff *skb) { int tx_index; struct eth_tx_desc *desc; u32 cmd_sts; int length; - int tx_bytes = 0; + int nr_frags = skb_shinfo(skb)->nr_frags; cmd_sts = ETH_TX_FIRST_DESC | ETH_GEN_CRC | ETH_BUFFER_OWNED_BY_DMA; tx_index = eth_alloc_tx_desc_index(mp); desc = &mp->p_tx_desc_area[tx_index]; - if (skb_shinfo(skb)->nr_frags) { + if (nr_frags) { eth_tx_fill_frag_descs(mp, skb); length = skb_headlen(skb); @@ -1244,7 +1228,6 @@ static int eth_tx_submit_descs_for_skb(struct mv643xx_private *mp, desc->byte_cnt = length; desc->buf_ptr = dma_map_single(NULL, skb->data, length, DMA_TO_DEVICE); - tx_bytes += length; if (skb->ip_summed == CHECKSUM_HW) { BUG_ON(skb->protocol != ETH_P_IP); @@ -1276,9 +1259,9 @@ static int eth_tx_submit_descs_for_skb(struct mv643xx_private *mp, /* ensure all descriptors are written before poking hardware */ wmb(); - mv643xx_eth_port_enable_tx(mp->port_num, mp->port_tx_queue_command); + mv643xx_eth_port_enable_tx(mp->port_num, ETH_TX_QUEUES_ENABLED); - return tx_bytes; + mp->tx_desc_count += nr_frags + 1; } /** @@ -1306,7 +1289,8 @@ static int mv643xx_eth_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irqsave(&mp->lock, flags); - stats->tx_bytes = eth_tx_submit_descs_for_skb(mp, skb); + eth_tx_submit_descs_for_skb(mp, skb); + stats->tx_bytes = skb->len; stats->tx_packets++; dev->trans_start = jiffies; @@ -1893,7 +1877,7 @@ static void eth_port_start(struct net_device *dev) MV643XX_ETH_PORT_SDMA_CONFIG_DEFAULT_VALUE); /* Enable port Rx. */ - mv643xx_eth_port_enable_rx(port_num, mp->port_rx_queue_command); + mv643xx_eth_port_enable_rx(port_num, ETH_RX_QUEUES_ENABLED); /* Disable port bandwidth limits by clearing MTU register */ mv_write(MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port_num), 0); @@ -2601,79 +2585,6 @@ static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, eth_port_write_smi_reg(mp->port_num, location, val); } -/* - * eth_tx_return_desc - Free all used Tx descriptors - * - * DESCRIPTION: - * This routine returns the transmitted packet information to the caller. - * It uses the 'first' index to support Tx desc return in case a transmit - * of a packet spanned over multiple buffer still in process. - * In case the Tx queue was in "resource error" condition, where there are - * no available Tx resources, the function resets the resource error flag. - * - * INPUT: - * struct mv643xx_private *mp Ethernet Port Control srtuct. - * struct pkt_info *p_pkt_info User packet buffer. - * - * OUTPUT: - * Tx ring 'first' and 'used' indexes are updated. - * - * RETURN: - * ETH_OK on success - * ETH_ERROR otherwise. - * - */ -static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, - struct pkt_info *p_pkt_info) -{ - int tx_desc_used; - struct eth_tx_desc *p_tx_desc_used; - unsigned int command_status; - unsigned long flags; - int err = ETH_OK; - - spin_lock_irqsave(&mp->lock, flags); - - BUG_ON(mp->tx_desc_count < 0); - if (mp->tx_desc_count == 0) { - /* no more tx descs in use */ - err = ETH_ERROR; - goto out; - } - - /* Get the Tx Desc ring indexes */ - tx_desc_used = mp->tx_used_desc_q; - - p_tx_desc_used = &mp->p_tx_desc_area[tx_desc_used]; - - BUG_ON(p_tx_desc_used == NULL); - - command_status = p_tx_desc_used->cmd_sts; - if (command_status & (ETH_BUFFER_OWNED_BY_DMA)) { - /* Still transmitting... */ - err = ETH_ERROR; - goto out; - } - - /* Pass the packet information to the caller */ - p_pkt_info->cmd_sts = command_status; - p_pkt_info->return_info = mp->tx_skb[tx_desc_used]; - p_pkt_info->buf_ptr = p_tx_desc_used->buf_ptr; - p_pkt_info->byte_cnt = p_tx_desc_used->byte_cnt; - mp->tx_skb[tx_desc_used] = NULL; - - /* Update the next descriptor to release. */ - mp->tx_used_desc_q = (tx_desc_used + 1) % mp->tx_ring_size; - - BUG_ON(mp->tx_desc_count == 0); - mp->tx_desc_count--; - -out: - spin_unlock_irqrestore(&mp->lock, flags); - - return err; -} - /* * eth_port_receive - Get received information from Rx ring. * diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index 8768e1ba45d..cade2705423 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -321,8 +321,6 @@ struct mv643xx_mib_counters { struct mv643xx_private { int port_num; /* User Ethernet port number */ - u32 port_tx_queue_command; /* Port active Tx queues summary*/ - u32 port_rx_queue_command; /* Port active Rx queues summary*/ u32 rx_sram_addr; /* Base address of rx sram area */ u32 rx_sram_size; /* Size of rx sram area */ @@ -411,8 +409,6 @@ static void eth_port_read_smi_reg(unsigned int eth_port_num, static void eth_clear_mib_counters(unsigned int eth_port_num); /* Port data flow control routines */ -static ETH_FUNC_RET_STATUS eth_tx_return_desc(struct mv643xx_private *mp, - struct pkt_info *p_pkt_info); static ETH_FUNC_RET_STATUS eth_port_receive(struct mv643xx_private *mp, struct pkt_info *p_pkt_info); static ETH_FUNC_RET_STATUS eth_rx_return_buff(struct mv643xx_private *mp, -- cgit v1.2.3 From 7303fde88a149c4cee54dae7e46d1895fa7214b4 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 3 Mar 2006 10:03:36 -0700 Subject: [PATCH] mv643xx_eth: Move #defines of constants to mv643xx_eth.h Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 66 +++++++++++++---------------------------------- drivers/net/mv643xx_eth.h | 47 +++++++++++++++++++++++---------- 2 files changed, 51 insertions(+), 62 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 8a24b39f3cc..50ee08518c6 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -50,37 +50,6 @@ #include #include "mv643xx_eth.h" -/* - * The first part is the high level driver of the gigE ethernet ports. - */ - -/* Constants */ -#define VLAN_HLEN 4 -#define FCS_LEN 4 -#define DMA_ALIGN 8 /* hw requires 8-byte alignment */ -#define HW_IP_ALIGN 2 /* hw aligns IP header */ -#define WRAP HW_IP_ALIGN + ETH_HLEN + VLAN_HLEN + FCS_LEN -#define RX_SKB_SIZE ((dev->mtu + WRAP + 7) & ~0x7) - -#define ETH_RX_QUEUES_ENABLED (1 << 0) /* use only Q0 for receive */ -#define ETH_TX_QUEUES_ENABLED (1 << 0) /* use only Q0 for transmit */ - -#define INT_UNMASK_ALL 0x0007ffff -#define INT_UNMASK_ALL_EXT 0x0011ffff -#define INT_MASK_ALL 0x00000000 -#define INT_MASK_ALL_EXT 0x00000000 -#define INT_CAUSE_CHECK_BITS INT_CAUSE_UNMASK_ALL -#define INT_CAUSE_CHECK_BITS_EXT INT_CAUSE_UNMASK_ALL_EXT - -#ifdef MV643XX_CHECKSUM_OFFLOAD_TX -#define MAX_DESCS_PER_SKB (MAX_SKB_FRAGS + 1) -#else -#define MAX_DESCS_PER_SKB 1 -#endif - -#define PHY_WAIT_ITERATIONS 1000 /* 1000 iterations * 10uS = 10mS max */ -#define PHY_WAIT_MICRO_SECONDS 10 - /* Static function declarations */ static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *MacAddr); @@ -182,24 +151,24 @@ static void mv643xx_eth_rx_task(void *data) panic("%s: Error in test_set_bit / clear_bit", dev->name); while (mp->rx_desc_count < (mp->rx_ring_size - 5)) { - skb = dev_alloc_skb(RX_SKB_SIZE + DMA_ALIGN); + skb = dev_alloc_skb(ETH_RX_SKB_SIZE + ETH_DMA_ALIGN); if (!skb) break; mp->rx_desc_count++; - unaligned = (u32)skb->data & (DMA_ALIGN - 1); + unaligned = (u32)skb->data & (ETH_DMA_ALIGN - 1); if (unaligned) - skb_reserve(skb, DMA_ALIGN - unaligned); + skb_reserve(skb, ETH_DMA_ALIGN - unaligned); pkt_info.cmd_sts = ETH_RX_ENABLE_INTERRUPT; - pkt_info.byte_cnt = RX_SKB_SIZE; - pkt_info.buf_ptr = dma_map_single(NULL, skb->data, RX_SKB_SIZE, - DMA_FROM_DEVICE); + pkt_info.byte_cnt = ETH_RX_SKB_SIZE; + pkt_info.buf_ptr = dma_map_single(NULL, skb->data, + ETH_RX_SKB_SIZE, DMA_FROM_DEVICE); pkt_info.return_info = skb; if (eth_rx_return_buff(mp, &pkt_info) != ETH_OK) { printk(KERN_ERR "%s: Error allocating RX Ring\n", dev->name); break; } - skb_reserve(skb, HW_IP_ALIGN); + skb_reserve(skb, ETH_HW_IP_ALIGN); } clear_bit(0, &mp->rx_task_busy); /* @@ -375,7 +344,7 @@ int mv643xx_eth_free_tx_descs(struct net_device *dev, int force) spin_unlock_irqrestore(&mp->lock, flags); - if (cmd_sts & BIT0) { + if (cmd_sts & ETH_ERROR_SUMMARY) { printk("%s: Error in TX\n", dev->name); mp->stats.tx_errors++; } @@ -562,12 +531,12 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, /* Read interrupt cause registers */ eth_int_cause = mv_read(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num)) & - INT_UNMASK_ALL; + ETH_INT_UNMASK_ALL; if (eth_int_cause & BIT1) eth_int_cause_ext = mv_read( MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) & - INT_UNMASK_ALL_EXT; + ETH_INT_UNMASK_ALL_EXT; #ifdef MV643XX_NAPI if (!(eth_int_cause & 0x0007fffd)) { @@ -591,7 +560,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, if (netif_rx_schedule_prep(dev)) { /* Mask all the interrupts */ mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), - INT_MASK_ALL); + ETH_INT_MASK_ALL); /* wait for previous write to complete */ mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); __netif_rx_schedule(dev); @@ -619,6 +588,7 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, #endif #endif } + /* PHY status changed */ if (eth_int_cause_ext & (BIT16 | BIT20)) { struct ethtool_cmd cmd; @@ -966,10 +936,10 @@ static int mv643xx_eth_open(struct net_device *dev) /* Unmask phy and link status changes interrupts */ mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), - INT_UNMASK_ALL_EXT); + ETH_INT_UNMASK_ALL_EXT); /* Unmask RX buffer and TX end interrupt */ - mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_UNMASK_ALL); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL); return 0; @@ -1049,7 +1019,7 @@ static int mv643xx_eth_stop(struct net_device *dev) unsigned int port_num = mp->port_num; /* Mask all interrupts on ethernet port */ - mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_MASK_ALL); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_MASK_ALL); /* wait for previous write to complete */ mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); @@ -1110,7 +1080,7 @@ static int mv643xx_poll(struct net_device *dev, int *budget) mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), - INT_UNMASK_ALL); + ETH_INT_UNMASK_ALL); } return done ? 0 : 1; @@ -1325,13 +1295,13 @@ static void mv643xx_netpoll(struct net_device *netdev) struct mv643xx_private *mp = netdev_priv(netdev); int port_num = mp->port_num; - mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_MASK_ALL); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_MASK_ALL); /* wait for previous write to complete */ mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); mv643xx_eth_int_handler(netdev->irq, netdev, NULL); - mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_UNMASK_ALL); + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL); } #endif diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index cade2705423..2e59f193e26 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -74,21 +74,40 @@ #define MV643XX_RX_COAL 100 #endif -/* - * The second part is the low level driver of the gigE ethernet ports. - */ +#ifdef MV643XX_CHECKSUM_OFFLOAD_TX +#define MAX_DESCS_PER_SKB (MAX_SKB_FRAGS + 1) +#else +#define MAX_DESCS_PER_SKB 1 +#endif -/* - * Header File for : MV-643xx network interface header - * - * DESCRIPTION: - * This header file contains macros typedefs and function declaration for - * the Marvell Gig Bit Ethernet Controller. - * - * DEPENDENCIES: - * None. - * - */ +#define ETH_VLAN_HLEN 4 +#define ETH_FCS_LEN 4 +#define ETH_DMA_ALIGN 8 /* hw requires 8-byte alignment */ +#define ETH_HW_IP_ALIGN 2 /* hw aligns IP header */ +#define ETH_WRAPPER_LEN (ETH_HW_IP_ALIGN + ETH_HLEN + \ + ETH_VLAN_HLEN + ETH_FCS_LEN) +#define ETH_RX_SKB_SIZE ((dev->mtu + ETH_WRAPPER_LEN + 7) & ~0x7) + +#define ETH_RX_QUEUES_ENABLED (1 << 0) /* use only Q0 for receive */ +#define ETH_TX_QUEUES_ENABLED (1 << 0) /* use only Q0 for transmit */ + +#define ETH_INT_CAUSE_RX_DONE (ETH_RX_QUEUES_ENABLED << 2) +#define ETH_INT_CAUSE_RX_ERROR (ETH_RX_QUEUES_ENABLED << 9) +#define ETH_INT_CAUSE_RX (ETH_INT_CAUSE_RX_DONE | ETH_INT_CAUSE_RX_ERROR) +#define ETH_INT_CAUSE_EXT 0x00000002 +#define ETH_INT_UNMASK_ALL (ETH_INT_CAUSE_RX | ETH_INT_CAUSE_EXT) + +#define ETH_INT_CAUSE_TX_DONE (ETH_TX_QUEUES_ENABLED << 0) +#define ETH_INT_CAUSE_TX_ERROR (ETH_TX_QUEUES_ENABLED << 8) +#define ETH_INT_CAUSE_TX (ETH_INT_CAUSE_TX_DONE | ETH_INT_CAUSE_TX_ERROR) +#define ETH_INT_CAUSE_PHY 0x00010000 +#define ETH_INT_UNMASK_ALL_EXT (ETH_INT_CAUSE_TX | ETH_INT_CAUSE_PHY) + +#define ETH_INT_MASK_ALL 0x00000000 +#define ETH_INT_MASK_ALL_EXT 0x00000000 + +#define PHY_WAIT_ITERATIONS 1000 /* 1000 iterations * 10uS = 10mS max */ +#define PHY_WAIT_MICRO_SECONDS 10 /* Buffer offset from buffer pointer */ #define RX_BUF_OFFSET 0x2 -- cgit v1.2.3 From 468d09f8946d40228c56de26fe4874b2f98067ed Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 3 Mar 2006 10:04:39 -0700 Subject: [PATCH] mv643xx_eth: Clean up interrupt handling Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 75 ++++++++++++++++------------------------------- drivers/net/mv643xx_eth.h | 5 ---- 2 files changed, 25 insertions(+), 55 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 50ee08518c6..30b0d5b1b15 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -388,11 +388,7 @@ static void mv643xx_eth_free_all_tx_descs(struct net_device *dev) * * Output : number of served packets */ -#ifdef MV643XX_NAPI static int mv643xx_eth_receive_queue(struct net_device *dev, int budget) -#else -static int mv643xx_eth_receive_queue(struct net_device *dev) -#endif { struct mv643xx_private *mp = netdev_priv(dev); struct net_device_stats *stats = &mp->stats; @@ -400,15 +396,14 @@ static int mv643xx_eth_receive_queue(struct net_device *dev) struct sk_buff *skb; struct pkt_info pkt_info; -#ifdef MV643XX_NAPI while (budget-- > 0 && eth_port_receive(mp, &pkt_info) == ETH_OK) { -#else - while (eth_port_receive(mp, &pkt_info) == ETH_OK) { -#endif mp->rx_desc_count--; received_packets++; - /* Update statistics. Note byte count includes 4 byte CRC count */ + /* + * Update statistics. + * Note byte count includes 4 byte CRC count + */ stats->rx_packets++; stats->rx_bytes += pkt_info.byte_cnt; skb = pkt_info.return_info; @@ -532,48 +527,10 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, /* Read interrupt cause registers */ eth_int_cause = mv_read(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num)) & ETH_INT_UNMASK_ALL; - - if (eth_int_cause & BIT1) + if (eth_int_cause & ETH_INT_CAUSE_EXT) { eth_int_cause_ext = mv_read( MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) & ETH_INT_UNMASK_ALL_EXT; - -#ifdef MV643XX_NAPI - if (!(eth_int_cause & 0x0007fffd)) { - /* Dont ack the Rx interrupt */ -#endif - /* - * Clear specific ethernet port intrerrupt registers by - * acknowleding relevant bits. - */ - mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), - ~eth_int_cause); - if (eth_int_cause_ext != 0x0) { - mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG - (port_num), ~eth_int_cause_ext); - /* UDP change : We may need this */ - if (eth_int_cause_ext & (BIT0 | BIT8)) - mv643xx_eth_free_completed_tx_descs(dev); - } -#ifdef MV643XX_NAPI - } else { - if (netif_rx_schedule_prep(dev)) { - /* Mask all the interrupts */ - mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), - ETH_INT_MASK_ALL); - /* wait for previous write to complete */ - mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); - __netif_rx_schedule(dev); - } -#else - if (eth_int_cause & (BIT2 | BIT11)) - mv643xx_eth_receive_queue(dev, 0); - - /* - * After forwarded received packets to upper layer, add a task - * in an interrupts enabled context that refills the RX ring - * with skb's. - */ #ifdef MV643XX_RX_QUEUE_FILL_ON_TASK /* Mask all interrupts on ethernet port */ mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), @@ -586,11 +543,12 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, #else mp->rx_task.func(dev); #endif -#endif + mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), + ~eth_int_cause_ext); } /* PHY status changed */ - if (eth_int_cause_ext & (BIT16 | BIT20)) { + if (eth_int_cause_ext & ETH_INT_CAUSE_PHY) { struct ethtool_cmd cmd; if (mii_link_ok(&mp->mii)) { @@ -610,6 +568,23 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, } } +#ifdef MV643XX_NAPI + if (eth_int_cause & ETH_INT_CAUSE_RX) { + /* schedule the NAPI poll routine to maintain port */ + mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), + ETH_INT_MASK_ALL); + /* wait for previous write to complete */ + mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); + + netif_rx_schedule(dev); + } +#else + if (eth_int_cause & ETH_INT_CAUSE_RX) + mv643xx_eth_receive_queue(dev, INT_MAX); + if (eth_int_cause_ext & ETH_INT_CAUSE_TX) + mv643xx_eth_free_completed_tx_descs(dev); +#endif + /* * If no real interrupt occured, exit. * This can happen when using gigE interrupt coalescing mechanism. diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index 2e59f193e26..df2c7615420 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -372,9 +372,6 @@ struct mv643xx_private { struct work_struct tx_timeout_task; - /* - * Former struct mv643xx_eth_priv members start here - */ struct net_device_stats stats; struct mv643xx_mib_counters mib_counters; spinlock_t lock; @@ -405,8 +402,6 @@ struct mv643xx_private { struct mii_if_info mii; }; -/* ethernet.h API list */ - /* Port operation control routines */ static void eth_port_init(struct mv643xx_private *mp); static void eth_port_reset(unsigned int eth_port_num); -- cgit v1.2.3 From f78fb4743dc06719084239c29dc178ad38ad2e2f Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 3 Mar 2006 10:05:26 -0700 Subject: [PATCH] mv643xx_eth: Remove non-working feature: task level rx queue refill The task level rx queue refill feature hasn't ever worked (at least in 2.6) and is of dubious value. Remove it. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.c | 59 ++++++++++------------------------------------- drivers/net/mv643xx_eth.h | 8 ------- 2 files changed, 12 insertions(+), 55 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 30b0d5b1b15..9f2661355a4 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -132,25 +132,21 @@ static int mv643xx_eth_change_mtu(struct net_device *dev, int new_mtu) } /* - * mv643xx_eth_rx_task + * mv643xx_eth_rx_refill_descs * * Fills / refills RX queue on a certain gigabit ethernet port * * Input : pointer to ethernet interface network device structure * Output : N/A */ -static void mv643xx_eth_rx_task(void *data) +static void mv643xx_eth_rx_refill_descs(struct net_device *dev) { - struct net_device *dev = (struct net_device *)data; struct mv643xx_private *mp = netdev_priv(dev); struct pkt_info pkt_info; struct sk_buff *skb; int unaligned; - if (test_and_set_bit(0, &mp->rx_task_busy)) - panic("%s: Error in test_set_bit / clear_bit", dev->name); - - while (mp->rx_desc_count < (mp->rx_ring_size - 5)) { + while (mp->rx_desc_count < mp->rx_ring_size) { skb = dev_alloc_skb(ETH_RX_SKB_SIZE + ETH_DMA_ALIGN); if (!skb) break; @@ -170,29 +166,19 @@ static void mv643xx_eth_rx_task(void *data) } skb_reserve(skb, ETH_HW_IP_ALIGN); } - clear_bit(0, &mp->rx_task_busy); /* * If RX ring is empty of SKB, set a timer to try allocating - * again in a later time . + * again at a later time. */ - if ((mp->rx_desc_count == 0) && (mp->rx_timer_flag == 0)) { + if (mp->rx_desc_count == 0) { printk(KERN_INFO "%s: Rx ring is empty\n", dev->name); - /* After 100mSec */ - mp->timeout.expires = jiffies + (HZ / 10); + mp->timeout.expires = jiffies + (HZ / 10); /* 100 mSec */ add_timer(&mp->timeout); - mp->rx_timer_flag = 1; - } -#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK - else { - /* Return interrupts */ - mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(mp->port_num), - INT_UNMASK_ALL); } -#endif } /* - * mv643xx_eth_rx_task_timer_wrapper + * mv643xx_eth_rx_refill_descs_timer_wrapper * * Timer routine to wake up RX queue filling task. This function is * used only in case the RX queue is empty, and all alloc_skb has @@ -201,13 +187,9 @@ static void mv643xx_eth_rx_task(void *data) * Input : pointer to ethernet interface network device structure * Output : N/A */ -static void mv643xx_eth_rx_task_timer_wrapper(unsigned long data) +static inline void mv643xx_eth_rx_refill_descs_timer_wrapper(unsigned long data) { - struct net_device *dev = (struct net_device *)data; - struct mv643xx_private *mp = netdev_priv(dev); - - mp->rx_timer_flag = 0; - mv643xx_eth_rx_task((void *)data); + mv643xx_eth_rx_refill_descs((struct net_device *)data); } /* @@ -451,6 +433,7 @@ static int mv643xx_eth_receive_queue(struct net_device *dev, int budget) } dev->last_rx = jiffies; } + mv643xx_eth_rx_refill_descs(dev); /* Fill RX ring with skb's */ return received_packets; } @@ -531,18 +514,6 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, eth_int_cause_ext = mv_read( MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num)) & ETH_INT_UNMASK_ALL_EXT; -#ifdef MV643XX_RX_QUEUE_FILL_ON_TASK - /* Mask all interrupts on ethernet port */ - mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), - INT_MASK_ALL); - /* wait for previous write to take effect */ - mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num)); - - queue_task(&mp->rx_task, &tq_immediate); - mark_bh(IMMEDIATE_BH); -#else - mp->rx_task.func(dev); -#endif mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), ~eth_int_cause_ext); } @@ -810,15 +781,10 @@ static int mv643xx_eth_open(struct net_device *dev) eth_port_init(mp); - INIT_WORK(&mp->rx_task, (void (*)(void *))mv643xx_eth_rx_task, dev); - memset(&mp->timeout, 0, sizeof(struct timer_list)); - mp->timeout.function = mv643xx_eth_rx_task_timer_wrapper; + mp->timeout.function = mv643xx_eth_rx_refill_descs_timer_wrapper; mp->timeout.data = (unsigned long)dev; - mp->rx_task_busy = 0; - mp->rx_timer_flag = 0; - /* Allocate RX and TX skb rings */ mp->rx_skb = kmalloc(sizeof(*mp->rx_skb) * mp->rx_ring_size, GFP_KERNEL); @@ -891,7 +857,7 @@ static int mv643xx_eth_open(struct net_device *dev) ether_init_rx_desc_ring(mp); - mv643xx_eth_rx_task(dev); /* Fill RX ring with skb's */ + mv643xx_eth_rx_refill_descs(dev); /* Fill RX ring with skb's */ /* Clear any pending ethernet port interrupts */ mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); @@ -1043,7 +1009,6 @@ static int mv643xx_poll(struct net_device *dev, int *budget) if (orig_budget > dev->quota) orig_budget = dev->quota; work_done = mv643xx_eth_receive_queue(dev, orig_budget); - mp->rx_task.func(dev); *budget -= work_done; dev->quota -= work_done; if (work_done >= orig_budget) diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index df2c7615420..f8742e1edea 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -52,7 +52,6 @@ #define MV643XX_CHECKSUM_OFFLOAD_TX #define MV643XX_NAPI #define MV643XX_TX_FAST_REFILL -#undef MV643XX_RX_QUEUE_FILL_ON_TASK /* Does not work, yet */ #undef MV643XX_COAL /* @@ -384,18 +383,11 @@ struct mv643xx_private { /* Number of rx descriptors in use */ int rx_desc_count; - /* - * rx_task used to fill RX ring out of bottom half context - */ - struct work_struct rx_task; - /* * Used in case RX Ring is empty, which can be caused when * system does not have resources (skb's) */ struct timer_list timeout; - long rx_task_busy __attribute__ ((aligned(SMP_CACHE_BYTES))); - unsigned rx_timer_flag; u32 rx_int_coal; u32 tx_int_coal; -- cgit v1.2.3 From ebe19a4ed78d4a11a7e01cdeda25f91b7f2fcb5a Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Fri, 3 Mar 2006 10:06:20 -0700 Subject: [PATCH] mv643xx_eth: Remove BIT0-BIT31 #defines Now that the BIT0-BIT31 defines are no longer used by mv643xx_eth.c, remove them from mv643xx_eth.h. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.h | 152 +++++++++++++++------------------------------- 1 file changed, 49 insertions(+), 103 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index f8742e1edea..7754d1974b9 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -9,43 +9,6 @@ #include -#define BIT0 0x00000001 -#define BIT1 0x00000002 -#define BIT2 0x00000004 -#define BIT3 0x00000008 -#define BIT4 0x00000010 -#define BIT5 0x00000020 -#define BIT6 0x00000040 -#define BIT7 0x00000080 -#define BIT8 0x00000100 -#define BIT9 0x00000200 -#define BIT10 0x00000400 -#define BIT11 0x00000800 -#define BIT12 0x00001000 -#define BIT13 0x00002000 -#define BIT14 0x00004000 -#define BIT15 0x00008000 -#define BIT16 0x00010000 -#define BIT17 0x00020000 -#define BIT18 0x00040000 -#define BIT19 0x00080000 -#define BIT20 0x00100000 -#define BIT21 0x00200000 -#define BIT22 0x00400000 -#define BIT23 0x00800000 -#define BIT24 0x01000000 -#define BIT25 0x02000000 -#define BIT26 0x04000000 -#define BIT27 0x08000000 -#define BIT28 0x10000000 -#define BIT29 0x20000000 -#define BIT30 0x40000000 -#define BIT31 0x80000000 - -/* - * The first part is the high level driver of the gigE ethernet ports. - */ - /* Checksum offload for Tx works for most packets, but * fails if previous packet sent did not use hw csum */ @@ -148,88 +111,71 @@ #define ETH_MIB_LATE_COLLISION 0x7c /* Port serial status reg (PSR) */ -#define ETH_INTERFACE_GMII_MII 0 -#define ETH_INTERFACE_PCM BIT0 -#define ETH_LINK_IS_DOWN 0 -#define ETH_LINK_IS_UP BIT1 -#define ETH_PORT_AT_HALF_DUPLEX 0 -#define ETH_PORT_AT_FULL_DUPLEX BIT2 -#define ETH_RX_FLOW_CTRL_DISABLED 0 -#define ETH_RX_FLOW_CTRL_ENBALED BIT3 -#define ETH_GMII_SPEED_100_10 0 -#define ETH_GMII_SPEED_1000 BIT4 -#define ETH_MII_SPEED_10 0 -#define ETH_MII_SPEED_100 BIT5 -#define ETH_NO_TX 0 -#define ETH_TX_IN_PROGRESS BIT7 -#define ETH_BYPASS_NO_ACTIVE 0 -#define ETH_BYPASS_ACTIVE BIT8 -#define ETH_PORT_NOT_AT_PARTITION_STATE 0 -#define ETH_PORT_AT_PARTITION_STATE BIT9 -#define ETH_PORT_TX_FIFO_NOT_EMPTY 0 -#define ETH_PORT_TX_FIFO_EMPTY BIT10 - -#define ETH_DEFAULT_RX_BPDU_QUEUE_3 (BIT23 | BIT22) -#define ETH_DEFAULT_RX_BPDU_QUEUE_4 BIT24 -#define ETH_DEFAULT_RX_BPDU_QUEUE_5 (BIT24 | BIT22) -#define ETH_DEFAULT_RX_BPDU_QUEUE_6 (BIT24 | BIT23) -#define ETH_DEFAULT_RX_BPDU_QUEUE_7 (BIT24 | BIT23 | BIT22) +#define ETH_INTERFACE_PCM 0x00000001 +#define ETH_LINK_IS_UP 0x00000002 +#define ETH_PORT_AT_FULL_DUPLEX 0x00000004 +#define ETH_RX_FLOW_CTRL_ENABLED 0x00000008 +#define ETH_GMII_SPEED_1000 0x00000010 +#define ETH_MII_SPEED_100 0x00000020 +#define ETH_TX_IN_PROGRESS 0x00000080 +#define ETH_BYPASS_ACTIVE 0x00000100 +#define ETH_PORT_AT_PARTITION_STATE 0x00000200 +#define ETH_PORT_TX_FIFO_EMPTY 0x00000400 /* SMI reg */ -#define ETH_SMI_BUSY BIT28 /* 0 - Write, 1 - Read */ -#define ETH_SMI_READ_VALID BIT27 /* 0 - Write, 1 - Read */ -#define ETH_SMI_OPCODE_WRITE 0 /* Completion of Read operation */ -#define ETH_SMI_OPCODE_READ BIT26 /* Operation is in progress */ +#define ETH_SMI_BUSY 0x10000000 /* 0 - Write, 1 - Read */ +#define ETH_SMI_READ_VALID 0x08000000 /* 0 - Write, 1 - Read */ +#define ETH_SMI_OPCODE_WRITE 0 /* Completion of Read */ +#define ETH_SMI_OPCODE_READ 0x04000000 /* Operation is in progress */ + +/* Interrupt Cause Register Bit Definitions */ /* SDMA command status fields macros */ /* Tx & Rx descriptors status */ -#define ETH_ERROR_SUMMARY (BIT0) +#define ETH_ERROR_SUMMARY 0x00000001 /* Tx & Rx descriptors command */ -#define ETH_BUFFER_OWNED_BY_DMA (BIT31) +#define ETH_BUFFER_OWNED_BY_DMA 0x80000000 /* Tx descriptors status */ -#define ETH_LC_ERROR (0 ) -#define ETH_UR_ERROR (BIT1 ) -#define ETH_RL_ERROR (BIT2 ) -#define ETH_LLC_SNAP_FORMAT (BIT9 ) +#define ETH_LC_ERROR 0 +#define ETH_UR_ERROR 0x00000002 +#define ETH_RL_ERROR 0x00000004 +#define ETH_LLC_SNAP_FORMAT 0x00000200 /* Rx descriptors status */ -#define ETH_CRC_ERROR (0 ) -#define ETH_OVERRUN_ERROR (BIT1 ) -#define ETH_MAX_FRAME_LENGTH_ERROR (BIT2 ) -#define ETH_RESOURCE_ERROR ((BIT2 | BIT1)) -#define ETH_VLAN_TAGGED (BIT19) -#define ETH_BPDU_FRAME (BIT20) -#define ETH_TCP_FRAME_OVER_IP_V_4 (0 ) -#define ETH_UDP_FRAME_OVER_IP_V_4 (BIT21) -#define ETH_OTHER_FRAME_TYPE (BIT22) -#define ETH_LAYER_2_IS_ETH_V_2 (BIT23) -#define ETH_FRAME_TYPE_IP_V_4 (BIT24) -#define ETH_FRAME_HEADER_OK (BIT25) -#define ETH_RX_LAST_DESC (BIT26) -#define ETH_RX_FIRST_DESC (BIT27) -#define ETH_UNKNOWN_DESTINATION_ADDR (BIT28) -#define ETH_RX_ENABLE_INTERRUPT (BIT29) -#define ETH_LAYER_4_CHECKSUM_OK (BIT30) +#define ETH_OVERRUN_ERROR 0x00000002 +#define ETH_MAX_FRAME_LENGTH_ERROR 0x00000004 +#define ETH_RESOURCE_ERROR 0x00000006 +#define ETH_VLAN_TAGGED 0x00080000 +#define ETH_BPDU_FRAME 0x00100000 +#define ETH_UDP_FRAME_OVER_IP_V_4 0x00200000 +#define ETH_OTHER_FRAME_TYPE 0x00400000 +#define ETH_LAYER_2_IS_ETH_V_2 0x00800000 +#define ETH_FRAME_TYPE_IP_V_4 0x01000000 +#define ETH_FRAME_HEADER_OK 0x02000000 +#define ETH_RX_LAST_DESC 0x04000000 +#define ETH_RX_FIRST_DESC 0x08000000 +#define ETH_UNKNOWN_DESTINATION_ADDR 0x10000000 +#define ETH_RX_ENABLE_INTERRUPT 0x20000000 +#define ETH_LAYER_4_CHECKSUM_OK 0x40000000 /* Rx descriptors byte count */ -#define ETH_FRAME_FRAGMENTED (BIT2) +#define ETH_FRAME_FRAGMENTED 0x00000004 /* Tx descriptors command */ -#define ETH_LAYER_4_CHECKSUM_FIRST_DESC (BIT10) -#define ETH_FRAME_SET_TO_VLAN (BIT15) -#define ETH_TCP_FRAME (0 ) -#define ETH_UDP_FRAME (BIT16) -#define ETH_GEN_TCP_UDP_CHECKSUM (BIT17) -#define ETH_GEN_IP_V_4_CHECKSUM (BIT18) -#define ETH_ZERO_PADDING (BIT19) -#define ETH_TX_LAST_DESC (BIT20) -#define ETH_TX_FIRST_DESC (BIT21) -#define ETH_GEN_CRC (BIT22) -#define ETH_TX_ENABLE_INTERRUPT (BIT23) -#define ETH_AUTO_MODE (BIT30) +#define ETH_LAYER_4_CHECKSUM_FIRST_DESC 0x00000400 +#define ETH_FRAME_SET_TO_VLAN 0x00008000 +#define ETH_UDP_FRAME 0x00010000 +#define ETH_GEN_TCP_UDP_CHECKSUM 0x00020000 +#define ETH_GEN_IP_V_4_CHECKSUM 0x00040000 +#define ETH_ZERO_PADDING 0x00080000 +#define ETH_TX_LAST_DESC 0x00100000 +#define ETH_TX_FIRST_DESC 0x00200000 +#define ETH_GEN_CRC 0x00400000 +#define ETH_TX_ENABLE_INTERRUPT 0x00800000 +#define ETH_AUTO_MODE 0x40000000 #define ETH_TX_IHL_SHIFT 11 -- cgit v1.2.3 From 8f903c708fcc2b579ebf16542bf6109bad593a1d Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Tue, 21 Feb 2006 16:36:44 -0800 Subject: [PATCH] bonding: suppress duplicate packets Originally submitted by Kenzo Iwami; his original description is: The current bonding driver receives duplicate packets when broadcast/ multicast packets are sent by other devices or packets are flooded by the switch. In this patch, new flags are added in priv_flags of net_device structure to let the bonding driver discard duplicate packets in dev.c:skb_bond(). Modified by Jay Vosburgh to change a define name, update some comments, rearrange the new skb_bond() for clarity, clear all bonding priv_flags on slave release, and update the driver version. Signed-off-by: Kenzo Iwami Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_main.c | 43 ++++++++++++++++++++-------------------- drivers/net/bonding/bond_sysfs.c | 6 ++++++ drivers/net/bonding/bonding.h | 33 +++++++++++++++++++++++++----- 3 files changed, 56 insertions(+), 26 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index bcf9f17daf0..623c87a8361 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -1040,6 +1040,10 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) if ((bond->params.mode == BOND_MODE_TLB) || (bond->params.mode == BOND_MODE_ALB)) { bond_alb_handle_active_change(bond, new_active); + if (old_active) + bond_set_slave_inactive_flags(old_active); + if (new_active) + bond_set_slave_active_flags(new_active); } else { bond->curr_active_slave = new_active; } @@ -1443,15 +1447,16 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) switch (bond->params.mode) { case BOND_MODE_ACTIVEBACKUP: - /* if we're in active-backup mode, we need one and only one active - * interface. The backup interfaces will have their NOARP flag set - * because we need them to be completely deaf and not to respond to - * any ARP request on the network to avoid fooling a switch. Thus, - * since we guarantee that curr_active_slave always point to the last - * usable interface, we just have to verify this interface's flag. + /* if we're in active-backup mode, we need one and + * only one active interface. The backup interfaces + * will have their SLAVE_INACTIVE flag set because we + * need them to be drop all packets. Thus, since we + * guarantee that curr_active_slave always point to + * the last usable interface, we just have to verify + * this interface's flag. */ if (((!bond->curr_active_slave) || - (bond->curr_active_slave->dev->flags & IFF_NOARP)) && + (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) && (new_slave->link != BOND_LINK_DOWN)) { dprintk("This is the first active slave\n"); /* first slave or no active slave yet, and this link @@ -1492,6 +1497,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * is OK, so make this interface the active one */ bond_change_active_slave(bond, new_slave); + } else { + bond_set_slave_inactive_flags(new_slave); } break; default: @@ -1724,13 +1731,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) addr.sa_family = slave_dev->type; dev_set_mac_address(slave_dev, &addr); - /* restore the original state of the - * IFF_NOARP flag that might have been - * set by bond_set_slave_inactive_flags() - */ - if ((slave->original_flags & IFF_NOARP) == 0) { - slave_dev->flags &= ~IFF_NOARP; - } + slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | + IFF_SLAVE_INACTIVE); kfree(slave); @@ -1816,12 +1818,8 @@ static int bond_release_all(struct net_device *bond_dev) addr.sa_family = slave_dev->type; dev_set_mac_address(slave_dev, &addr); - /* restore the original state of the IFF_NOARP flag that might have - * been set by bond_set_slave_inactive_flags() - */ - if ((slave->original_flags & IFF_NOARP) == 0) { - slave_dev->flags &= ~IFF_NOARP; - } + slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB | + IFF_SLAVE_INACTIVE); kfree(slave); @@ -4061,14 +4059,17 @@ void bond_set_mode_ops(struct bonding *bond, int mode) bond_dev->hard_start_xmit = bond_xmit_broadcast; break; case BOND_MODE_8023AD: + bond_set_master_3ad_flags(bond); bond_dev->hard_start_xmit = bond_3ad_xmit_xor; if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34) bond->xmit_hash_policy = bond_xmit_hash_policy_l34; else bond->xmit_hash_policy = bond_xmit_hash_policy_l2; break; - case BOND_MODE_TLB: case BOND_MODE_ALB: + bond_set_master_alb_flags(bond); + /* FALLTHRU */ + case BOND_MODE_TLB: bond_dev->hard_start_xmit = bond_alb_xmit; bond_dev->set_mac_address = bond_alb_set_mac_address; break; diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 041bcc58355..5a9bd95884b 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -424,6 +424,12 @@ static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size ret = -EINVAL; goto out; } else { + if (bond->params.mode == BOND_MODE_8023AD) + bond_unset_master_3ad_flags(bond); + + if (bond->params.mode == BOND_MODE_ALB) + bond_unset_master_alb_flags(bond); + bond->params.mode = new_value; bond_set_mode_ops(bond, bond->params.mode); printk(KERN_INFO DRV_NAME ": %s: setting mode to %s (%d).\n", diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 3dd78d048c3..ce9dc9b4e2d 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -22,8 +22,8 @@ #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.0.1" -#define DRV_RELDATE "January 9, 2006" +#define DRV_VERSION "3.0.2" +#define DRV_RELDATE "February 21, 2006" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" @@ -230,14 +230,37 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) static inline void bond_set_slave_inactive_flags(struct slave *slave) { - slave->state = BOND_STATE_BACKUP; - slave->dev->flags |= IFF_NOARP; + struct bonding *bond = slave->dev->master->priv; + if (bond->params.mode != BOND_MODE_TLB && + bond->params.mode != BOND_MODE_ALB) + slave->state = BOND_STATE_BACKUP; + slave->dev->priv_flags |= IFF_SLAVE_INACTIVE; } static inline void bond_set_slave_active_flags(struct slave *slave) { slave->state = BOND_STATE_ACTIVE; - slave->dev->flags &= ~IFF_NOARP; + slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE; +} + +static inline void bond_set_master_3ad_flags(struct bonding *bond) +{ + bond->dev->priv_flags |= IFF_MASTER_8023AD; +} + +static inline void bond_unset_master_3ad_flags(struct bonding *bond) +{ + bond->dev->priv_flags &= ~IFF_MASTER_8023AD; +} + +static inline void bond_set_master_alb_flags(struct bonding *bond) +{ + bond->dev->priv_flags |= IFF_MASTER_ALB; +} + +static inline void bond_unset_master_alb_flags(struct bonding *bond) +{ + bond->dev->priv_flags &= ~IFF_MASTER_ALB; } struct vlan_entry *bond_next_vlan(struct bonding *bond, struct vlan_entry *curr); -- cgit v1.2.3 From c96a34ec3bad5ba37ee4da4a188ad534b2fa4321 Mon Sep 17 00:00:00 2001 From: Komuro Date: Fri, 3 Mar 2006 21:21:13 -0500 Subject: pcnet_cs: add new id (Logitec LPM-LN100TE) --- drivers/net/pcmcia/pcnet_cs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index d85b758f3ef..736dff5fa93 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -1727,6 +1727,7 @@ static struct pcmcia_device_id pcnet_ids[] = { PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V2)", 0x0733cc81, 0x3a3b28e9), PCMCIA_DEVICE_PROD_ID12("Linksys", "HomeLink Phoneline + 10/100 Network PC Card (PCM100H1)", 0x733cc81, 0x7a3e5c3a), PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TX", 0x88fcdeda, 0x6d772737), + PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TE", 0x88fcdeda, 0x0e714bee), PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN20T", 0x88fcdeda, 0x81090922), PCMCIA_DEVICE_PROD_ID12("LONGSHINE", "PCMCIA Ethernet Card", 0xf866b0b0, 0x6f6652e0), PCMCIA_DEVICE_PROD_ID12("MACNICA", "ME1-JEIDA", 0x20841b68, 0xaf8a3578), -- cgit v1.2.3 From f90fdc3cce3d8c8ed09615dc68cb789655078803 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 8 Feb 2006 23:23:26 +0000 Subject: [PATCH] sb1250-mac: Add support for the BCM1480 This adds support for the 4th port and other new features of the BCM1480 SOC. Signed-Off-By: Andy Isaacson Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik --- drivers/net/sb1250-mac.c | 109 ++++++++++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 39 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index aa4ca182175..f2be9f83f09 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2001,2002,2003 Broadcom Corporation + * Copyright (C) 2001,2002,2003,2004 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -43,6 +43,7 @@ #define SBMAC_ETH0_HWADDR "40:00:00:00:01:00" #define SBMAC_ETH1_HWADDR "40:00:00:00:01:01" #define SBMAC_ETH2_HWADDR "40:00:00:00:01:02" +#define SBMAC_ETH3_HWADDR "40:00:00:00:01:03" #endif @@ -57,7 +58,7 @@ static char version1[] __devinitdata = #define CONFIG_SBMAC_COALESCE -#define MAX_UNITS 3 /* More are supported, limit only on options */ +#define MAX_UNITS 4 /* More are supported, limit only on options */ /* Time in jiffies before concluding the transmitter is hung. */ #define TX_TIMEOUT (2*HZ) @@ -85,11 +86,11 @@ MODULE_PARM_DESC(noisy_mii, "MII status messages"); The media type is usually passed in 'options[]'. */ #ifdef MODULE -static int options[MAX_UNITS] = {-1, -1, -1}; +static int options[MAX_UNITS] = {-1, -1, -1, -1}; module_param_array(options, int, NULL, S_IRUGO); MODULE_PARM_DESC(options, "1-" __MODULE_STRING(MAX_UNITS)); -static int full_duplex[MAX_UNITS] = {-1, -1, -1}; +static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1}; module_param_array(full_duplex, int, NULL, S_IRUGO); MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS)); #endif @@ -105,13 +106,26 @@ MODULE_PARM_DESC(int_timeout, "Timeout value"); #endif #include -#include +#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#include +#include +#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) #include -#include -#include #include +#else +#error invalid SiByte MAC configuation +#endif #include +#include +#include +#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) +#define UNIT_INT(n) (K_BCM1480_INT_MAC_0 + ((n) * 2)) +#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) +#define UNIT_INT(n) (K_INT_MAC_0 + (n)) +#else +#error invalid SiByte MAC configuation +#endif /********************************************************************** * Simple types @@ -1476,10 +1490,10 @@ static void sbmac_channel_start(struct sbmac_softc *s) * and make sure that RD_THRSH + WR_THRSH <=128 for pass2 and above * Use a larger RD_THRSH for gigabit */ - if (periph_rev >= 2) - th_value = 64; - else + if (soc_type == K_SYS_SOC_TYPE_BCM1250 && periph_rev < 2) th_value = 28; + else + th_value = 64; fifo = V_MAC_TX_WR_THRSH(4) | /* Must be '4' or '8' */ ((s->sbm_speed == sbmac_speed_1000) @@ -1589,13 +1603,17 @@ static void sbmac_channel_start(struct sbmac_softc *s) * Turn on the rest of the bits in the enable register */ +#if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) + __raw_writeq(M_MAC_RXDMA_EN0 | + M_MAC_TXDMA_EN0, s->sbm_macenable); +#elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) __raw_writeq(M_MAC_RXDMA_EN0 | M_MAC_TXDMA_EN0 | M_MAC_RX_ENABLE | M_MAC_TX_ENABLE, s->sbm_macenable); - - - +#else +#error invalid SiByte MAC configuation +#endif #ifdef CONFIG_SBMAC_COALESCE /* @@ -1786,11 +1804,12 @@ static void sbmac_set_iphdr_offset(struct sbmac_softc *sc) reg &= ~M_MAC_IPHDR_OFFSET | V_MAC_IPHDR_OFFSET(15); __raw_writeq(reg, sc->sbm_rxfilter); - /* read system identification to determine revision */ - if (periph_rev >= 2) { - sc->rx_hw_checksum = ENABLE; - } else { + /* BCM1250 pass1 didn't have hardware checksum. Everything + later does. */ + if (soc_type == K_SYS_SOC_TYPE_BCM1250 && periph_rev < 2) { sc->rx_hw_checksum = DISABLE; + } else { + sc->rx_hw_checksum = ENABLE; } } @@ -2220,7 +2239,7 @@ static void sbmac_setmulti(struct sbmac_softc *sc) -#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) +#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR) /********************************************************************** * SBMAC_PARSE_XDIGIT(str) * @@ -2792,7 +2811,7 @@ static int sbmac_close(struct net_device *dev) -#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) +#if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR) static void sbmac_setup_hwaddr(int chan,char *addr) { @@ -2818,25 +2837,7 @@ sbmac_init_module(void) unsigned long port; int chip_max_units; - /* - * For bringup when not using the firmware, we can pre-fill - * the MAC addresses using the environment variables - * specified in this file (or maybe from the config file?) - */ -#ifdef SBMAC_ETH0_HWADDR - sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR); -#endif -#ifdef SBMAC_ETH1_HWADDR - sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR); -#endif -#ifdef SBMAC_ETH2_HWADDR - sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR); -#endif - - /* - * Walk through the Ethernet controllers and find - * those who have their MAC addresses set. - */ + /* Set the number of available units based on the SOC type. */ switch (soc_type) { case K_SYS_SOC_TYPE_BCM1250: case K_SYS_SOC_TYPE_BCM1250_ALT: @@ -2848,6 +2849,10 @@ sbmac_init_module(void) case K_SYS_SOC_TYPE_BCM1250_ALT2: /* Hybrid */ chip_max_units = 2; break; + case K_SYS_SOC_TYPE_BCM1x55: + case K_SYS_SOC_TYPE_BCM1x80: + chip_max_units = 4; + break; default: chip_max_units = 0; break; @@ -2855,6 +2860,32 @@ sbmac_init_module(void) if (chip_max_units > MAX_UNITS) chip_max_units = MAX_UNITS; + /* + * For bringup when not using the firmware, we can pre-fill + * the MAC addresses using the environment variables + * specified in this file (or maybe from the config file?) + */ +#ifdef SBMAC_ETH0_HWADDR + if (chip_max_units > 0) + sbmac_setup_hwaddr(0,SBMAC_ETH0_HWADDR); +#endif +#ifdef SBMAC_ETH1_HWADDR + if (chip_max_units > 1) + sbmac_setup_hwaddr(1,SBMAC_ETH1_HWADDR); +#endif +#ifdef SBMAC_ETH2_HWADDR + if (chip_max_units > 2) + sbmac_setup_hwaddr(2,SBMAC_ETH2_HWADDR); +#endif +#ifdef SBMAC_ETH3_HWADDR + if (chip_max_units > 3) + sbmac_setup_hwaddr(3,SBMAC_ETH3_HWADDR); +#endif + + /* + * Walk through the Ethernet controllers and find + * those who have their MAC addresses set. + */ for (idx = 0; idx < chip_max_units; idx++) { /* @@ -2886,7 +2917,7 @@ sbmac_init_module(void) printk(KERN_DEBUG "sbmac: configuring MAC at %lx\n", port); - dev->irq = K_INT_MAC_0 + idx; + dev->irq = UNIT_INT(idx); dev->base_addr = port; dev->mem_end = 0; if (sbmac_init(dev, idx)) { -- cgit v1.2.3 From f71e130966ba429dbd24be08ddbcdf263df9a5ad Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Fri, 3 Mar 2006 21:33:57 -0500 Subject: Massive net driver const-ification. --- drivers/net/3c59x.c | 4 +- drivers/net/8139cp.c | 2 +- drivers/net/8139too.c | 4 +- drivers/net/bnx2.c | 10 ++--- drivers/net/bnx2_fw.h | 84 ++++++++++++++++++++-------------------- drivers/net/bonding/bond_alb.c | 2 +- drivers/net/bonding/bond_main.c | 2 +- drivers/net/chelsio/subr.c | 2 +- drivers/net/dgrs.c | 2 +- drivers/net/dgrs_firmware.c | 4 +- drivers/net/dl2k.c | 4 +- drivers/net/eepro100.c | 4 +- drivers/net/epic100.c | 4 +- drivers/net/fealnx.c | 2 +- drivers/net/hamachi.c | 2 +- drivers/net/natsemi.c | 4 +- drivers/net/ne2k-pci.c | 2 +- drivers/net/ns83820.c | 2 +- drivers/net/pcmcia/3c574_cs.c | 2 +- drivers/net/pcmcia/3c589_cs.c | 2 +- drivers/net/pcmcia/fmvj18x_cs.c | 2 +- drivers/net/pcmcia/nmclan_cs.c | 2 +- drivers/net/pcmcia/pcnet_cs.c | 2 +- drivers/net/pcmcia/smc91c92_cs.c | 4 +- drivers/net/pcmcia/xirc2ps_cs.c | 2 +- drivers/net/pcnet32.c | 6 +-- drivers/net/phy/phy.c | 2 +- drivers/net/plip.c | 4 +- drivers/net/ppp_synctty.c | 2 +- drivers/net/r8169.c | 4 +- drivers/net/s2io.c | 8 ++-- drivers/net/sb1000.c | 2 +- drivers/net/sis190.c | 2 +- drivers/net/sis900.c | 8 ++-- drivers/net/skfp/fplustm.c | 14 +++---- drivers/net/skfp/pcmplc.c | 4 +- drivers/net/skfp/skfddi.c | 2 +- drivers/net/starfire.c | 4 +- drivers/net/sundance.c | 4 +- drivers/net/sungem_phy.c | 2 +- drivers/net/tg3.c | 4 +- drivers/net/typhoon.c | 2 +- drivers/net/yellowfin.c | 6 +-- 43 files changed, 118 insertions(+), 118 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 7f47124f118..26212a965ca 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -841,7 +841,7 @@ enum xcvr_types { XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10, }; -static struct media_table { +static const struct media_table { char *name; unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */ mask:8, /* The transceiver-present bit in Wn3_Config.*/ @@ -1445,7 +1445,7 @@ static int __devinit vortex_probe1(struct device *gendev, } { - static const char * ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; + static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; unsigned int config; EL3WINDOW(3); vp->available_media = ioread16(ioaddr + Wn3_Options); diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index dd410496aad..ce99845d826 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -1276,7 +1276,7 @@ static int cp_change_mtu(struct net_device *dev, int new_mtu) } #endif /* BROKEN */ -static char mii_2_8139_map[8] = { +static const char mii_2_8139_map[8] = { BasicModeCtrl, BasicModeStatus, 0, diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 2beac55b57d..e58d4c50c2e 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -229,7 +229,7 @@ typedef enum { /* indexed by board_t, above */ -static struct { +static const struct { const char *name; u32 hw_flags; } board_info[] __devinitdata = { @@ -1192,7 +1192,7 @@ static int __devinit read_eeprom (void __iomem *ioaddr, int location, int addr_l #define mdio_delay() RTL_R8(Config4) -static char mii_2_8139_map[8] = { +static const char mii_2_8139_map[8] = { BasicModeCtrl, BasicModeStatus, 0, diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index a24200d0a61..b787b6582e5 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -46,7 +46,7 @@ typedef enum { } board_t; /* indexed by board_t, above */ -static struct { +static const struct { char *name; } board_info[] __devinitdata = { { "Broadcom NetXtreme II BCM5706 1000Base-T" }, @@ -3476,7 +3476,7 @@ bnx2_test_registers(struct bnx2 *bp) { int ret; int i; - static struct { + static const struct { u16 offset; u16 flags; u32 rw_mask; @@ -3891,7 +3891,7 @@ reg_test_err: static int bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size) { - static u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555, + static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555, 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa }; int i; @@ -3916,7 +3916,7 @@ bnx2_test_memory(struct bnx2 *bp) { int ret = 0; int i; - static struct { + static const struct { u32 offset; u32 len; } mem_tbl[] = { @@ -5122,7 +5122,7 @@ static struct { #define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4) -static unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = { +static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = { STATS_OFFSET32(stat_IfHCInOctets_hi), STATS_OFFSET32(stat_IfHCInBadOctets_hi), STATS_OFFSET32(stat_IfHCOutOctets_hi), diff --git a/drivers/net/bnx2_fw.h b/drivers/net/bnx2_fw.h index 0c21bd84981..8158974c35a 100644 --- a/drivers/net/bnx2_fw.h +++ b/drivers/net/bnx2_fw.h @@ -14,20 +14,20 @@ * accompanying it. */ -static int bnx2_COM_b06FwReleaseMajor = 0x1; -static int bnx2_COM_b06FwReleaseMinor = 0x0; -static int bnx2_COM_b06FwReleaseFix = 0x0; -static u32 bnx2_COM_b06FwStartAddr = 0x080008b4; -static u32 bnx2_COM_b06FwTextAddr = 0x08000000; -static int bnx2_COM_b06FwTextLen = 0x57bc; -static u32 bnx2_COM_b06FwDataAddr = 0x08005840; -static int bnx2_COM_b06FwDataLen = 0x0; -static u32 bnx2_COM_b06FwRodataAddr = 0x080057c0; -static int bnx2_COM_b06FwRodataLen = 0x58; -static u32 bnx2_COM_b06FwBssAddr = 0x08005860; -static int bnx2_COM_b06FwBssLen = 0x88; -static u32 bnx2_COM_b06FwSbssAddr = 0x08005840; -static int bnx2_COM_b06FwSbssLen = 0x1c; +static const int bnx2_COM_b06FwReleaseMajor = 0x1; +static const int bnx2_COM_b06FwReleaseMinor = 0x0; +static const int bnx2_COM_b06FwReleaseFix = 0x0; +static const u32 bnx2_COM_b06FwStartAddr = 0x080008b4; +static const u32 bnx2_COM_b06FwTextAddr = 0x08000000; +static const int bnx2_COM_b06FwTextLen = 0x57bc; +static const u32 bnx2_COM_b06FwDataAddr = 0x08005840; +static const int bnx2_COM_b06FwDataLen = 0x0; +static const u32 bnx2_COM_b06FwRodataAddr = 0x080057c0; +static const int bnx2_COM_b06FwRodataLen = 0x58; +static const u32 bnx2_COM_b06FwBssAddr = 0x08005860; +static const int bnx2_COM_b06FwBssLen = 0x88; +static const u32 bnx2_COM_b06FwSbssAddr = 0x08005840; +static const int bnx2_COM_b06FwSbssLen = 0x1c; static u32 bnx2_COM_b06FwText[(0x57bc/4) + 1] = { 0x0a00022d, 0x00000000, 0x00000000, 0x0000000d, 0x636f6d20, 0x322e352e, 0x38000000, 0x02050802, 0x00000000, 0x00000003, 0x00000014, 0x00000032, @@ -2325,20 +2325,20 @@ static u32 bnx2_rv2p_proc2[] = { 0x0000000c, 0x29520000, 0x00000018, 0x80000002, 0x0000000c, 0x29800000, 0x00000018, 0x00570000 }; -static int bnx2_TPAT_b06FwReleaseMajor = 0x1; -static int bnx2_TPAT_b06FwReleaseMinor = 0x0; -static int bnx2_TPAT_b06FwReleaseFix = 0x0; -static u32 bnx2_TPAT_b06FwStartAddr = 0x08000860; -static u32 bnx2_TPAT_b06FwTextAddr = 0x08000800; -static int bnx2_TPAT_b06FwTextLen = 0x122c; -static u32 bnx2_TPAT_b06FwDataAddr = 0x08001a60; -static int bnx2_TPAT_b06FwDataLen = 0x0; -static u32 bnx2_TPAT_b06FwRodataAddr = 0x00000000; -static int bnx2_TPAT_b06FwRodataLen = 0x0; -static u32 bnx2_TPAT_b06FwBssAddr = 0x08001aa0; -static int bnx2_TPAT_b06FwBssLen = 0x250; -static u32 bnx2_TPAT_b06FwSbssAddr = 0x08001a60; -static int bnx2_TPAT_b06FwSbssLen = 0x34; +static const int bnx2_TPAT_b06FwReleaseMajor = 0x1; +static const int bnx2_TPAT_b06FwReleaseMinor = 0x0; +static const int bnx2_TPAT_b06FwReleaseFix = 0x0; +static const u32 bnx2_TPAT_b06FwStartAddr = 0x08000860; +static const u32 bnx2_TPAT_b06FwTextAddr = 0x08000800; +static const int bnx2_TPAT_b06FwTextLen = 0x122c; +static const u32 bnx2_TPAT_b06FwDataAddr = 0x08001a60; +static const int bnx2_TPAT_b06FwDataLen = 0x0; +static const u32 bnx2_TPAT_b06FwRodataAddr = 0x00000000; +static const int bnx2_TPAT_b06FwRodataLen = 0x0; +static const u32 bnx2_TPAT_b06FwBssAddr = 0x08001aa0; +static const int bnx2_TPAT_b06FwBssLen = 0x250; +static const u32 bnx2_TPAT_b06FwSbssAddr = 0x08001a60; +static const int bnx2_TPAT_b06FwSbssLen = 0x34; static u32 bnx2_TPAT_b06FwText[(0x122c/4) + 1] = { 0x0a000218, 0x00000000, 0x00000000, 0x0000000d, 0x74706174, 0x20322e35, 0x2e313100, 0x02050b01, 0x00000000, 0x00000000, 0x00000000, 0x00000000, @@ -2540,20 +2540,20 @@ static u32 bnx2_TPAT_b06FwRodata[(0x0/4) + 1] = { 0x0 }; static u32 bnx2_TPAT_b06FwBss[(0x250/4) + 1] = { 0x0 }; static u32 bnx2_TPAT_b06FwSbss[(0x34/4) + 1] = { 0x0 }; -static int bnx2_TXP_b06FwReleaseMajor = 0x1; -static int bnx2_TXP_b06FwReleaseMinor = 0x0; -static int bnx2_TXP_b06FwReleaseFix = 0x0; -static u32 bnx2_TXP_b06FwStartAddr = 0x080034b0; -static u32 bnx2_TXP_b06FwTextAddr = 0x08000000; -static int bnx2_TXP_b06FwTextLen = 0x5748; -static u32 bnx2_TXP_b06FwDataAddr = 0x08005760; -static int bnx2_TXP_b06FwDataLen = 0x0; -static u32 bnx2_TXP_b06FwRodataAddr = 0x00000000; -static int bnx2_TXP_b06FwRodataLen = 0x0; -static u32 bnx2_TXP_b06FwBssAddr = 0x080057a0; -static int bnx2_TXP_b06FwBssLen = 0x1c4; -static u32 bnx2_TXP_b06FwSbssAddr = 0x08005760; -static int bnx2_TXP_b06FwSbssLen = 0x38; +static const int bnx2_TXP_b06FwReleaseMajor = 0x1; +static const int bnx2_TXP_b06FwReleaseMinor = 0x0; +static const int bnx2_TXP_b06FwReleaseFix = 0x0; +static const u32 bnx2_TXP_b06FwStartAddr = 0x080034b0; +static const u32 bnx2_TXP_b06FwTextAddr = 0x08000000; +static const int bnx2_TXP_b06FwTextLen = 0x5748; +static const u32 bnx2_TXP_b06FwDataAddr = 0x08005760; +static const int bnx2_TXP_b06FwDataLen = 0x0; +static const u32 bnx2_TXP_b06FwRodataAddr = 0x00000000; +static const int bnx2_TXP_b06FwRodataLen = 0x0; +static const u32 bnx2_TXP_b06FwBssAddr = 0x080057a0; +static const int bnx2_TXP_b06FwBssLen = 0x1c4; +static const u32 bnx2_TXP_b06FwSbssAddr = 0x08005760; +static const int bnx2_TXP_b06FwSbssLen = 0x38; static u32 bnx2_TXP_b06FwText[(0x5748/4) + 1] = { 0x0a000d2c, 0x00000000, 0x00000000, 0x0000000d, 0x74787020, 0x322e352e, 0x38000000, 0x02050800, 0x0000000a, 0x000003e8, 0x0000ea60, 0x00000000, diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index f2a63186ae0..e83bc825f6a 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -1261,7 +1261,7 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) struct ethhdr *eth_data; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *tx_slave = NULL; - static u32 ip_bcast = 0xffffffff; + static const u32 ip_bcast = 0xffffffff; int hash_size = 0; int do_tx_balance = 1; u32 hash_index = 0; diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index bcf9f17daf0..d0c54ea55fb 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -131,7 +131,7 @@ MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form"); /*----------------------------- Global variables ----------------------------*/ -static const char *version = +static const char * const version = DRV_DESCRIPTION ": v" DRV_VERSION " (" DRV_RELDATE ")\n"; LIST_HEAD(bond_dev_list); diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index 1ebb5d149ae..12e4e96dba2 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c @@ -686,7 +686,7 @@ int t1_init_hw_modules(adapter_t *adapter) */ static void __devinit get_pci_mode(adapter_t *adapter, struct chelsio_pci_params *p) { - static unsigned short speed_map[] = { 33, 66, 100, 133 }; + static const unsigned short speed_map[] = { 33, 66, 100, 133 }; u32 pci_mode; pci_read_config_dword(adapter->pdev, A_PCICFG_MODE, &pci_mode); diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index 70b47e4c4e9..32d13166c6e 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -993,7 +993,7 @@ dgrs_download(struct net_device *dev0) int is; unsigned long i; - static int iv2is[16] = { + static const int iv2is[16] = { 0, 0, 0, ES4H_IS_INT3, 0, ES4H_IS_INT5, 0, ES4H_IS_INT7, 0, 0, ES4H_IS_INT10, ES4H_IS_INT11, diff --git a/drivers/net/dgrs_firmware.c b/drivers/net/dgrs_firmware.c index 1e49e1e1f20..8c20d4c9993 100644 --- a/drivers/net/dgrs_firmware.c +++ b/drivers/net/dgrs_firmware.c @@ -1,4 +1,4 @@ -static int dgrs_firmnum = 550; +static const int dgrs_firmnum = 550; static char dgrs_firmver[] = "$Version$"; static char dgrs_firmdate[] = "11/16/96 03:45:15"; static unsigned char dgrs_code[] __initdata = { @@ -9963,4 +9963,4 @@ static unsigned char dgrs_code[] __initdata = { 109,46,99,0,114,99,0,0,48,120,0,0, 0,0,0,0,0,0,0,0,0,0,0,0 } ; -static int dgrs_ncode = 119520 ; +static const int dgrs_ncode = 119520 ; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index 430c628279b..6376b63d9b1 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -90,8 +90,8 @@ module_param(tx_coalesce, int, 0); /* HW xmit count each TxDMAComplete */ #define EnableInt() \ writew(DEFAULT_INTR, ioaddr + IntEnable) -static int max_intrloop = 50; -static int multicast_filter_limit = 0x40; +static const int max_intrloop = 50; +static const int multicast_filter_limit = 0x40; static int rio_open (struct net_device *dev); static void rio_timer (unsigned long data); diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 8c62ced2c9b..467fc861360 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -27,7 +27,7 @@ rx_align support: enables rx DMA without causing unaligned accesses. */ -static const char *version = +static const char * const version = "eepro100.c:v1.09j-t 9/29/99 Donald Becker http://www.scyld.com/network/eepro100.html\n" "eepro100.c: $Revision: 1.36 $ 2000/11/17 Modified by Andrey V. Savochkin and others\n"; @@ -469,7 +469,7 @@ static const char i82558_config_cmd[CONFIG_DATA_SIZE] = { 0x31, 0x05, }; /* PHY media interface chips. */ -static const char *phys[] = { +static const char * const phys[] = { "None", "i82553-A/B", "i82553-C", "i82503", "DP83840", "80c240", "80c24", "i82555", "unknown-8", "unknown-9", "DP83840A", "unknown-11", diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index f119ec4e89e..2f7b86837fe 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -225,7 +225,7 @@ struct epic_chip_info { /* indexed by chip_t */ -static struct epic_chip_info pci_id_tbl[] = { +static const struct epic_chip_info pci_id_tbl[] = { { "SMSC EPIC/100 83c170", EPIC_IOTYPE, EPIC_TOTAL_SIZE, TYPE2_INTR | NO_MII | MII_PWRDWN }, { "SMSC EPIC/100 83c170", @@ -291,7 +291,7 @@ enum CommandBits { RxDone | RxStarted | RxEarlyWarn | RxOverflow | RxFull) #define EpicNormalEvent (0x0000ffff & ~EpicNapiEvent) -static u16 media2miictl[16] = { +static const u16 media2miictl[16] = { 0, 0x0C00, 0x0C00, 0x2000, 0x0100, 0x2100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index 55dbe9a3fd5..a8449265e5f 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -160,7 +160,7 @@ struct chip_info { int flags; }; -static struct chip_info skel_netdrv_tbl[] = { +static const struct chip_info skel_netdrv_tbl[] = { {"100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR}, {"100/10M Ethernet PCI Adapter", 136, HAS_CHIP_XCVR}, {"1000/100/10M Ethernet PCI Adapter", 136, HAS_MII_XCVR}, diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index bc9a3bf8d56..0ea4cb4a0d8 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -427,7 +427,7 @@ that case. static void hamachi_timer(unsigned long data); enum capability_flags {CanHaveMII=1, }; -static struct chip_info { +static const struct chip_info { u16 vendor_id, device_id, device_id_mask, pad; const char *name; void (*media_timer)(unsigned long data); diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 9d6d2548c2d..01920648fc3 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -189,7 +189,7 @@ static int mtu; /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). This chip uses a 512 element hash table based on the Ethernet CRC. */ -static int multicast_filter_limit = 100; +static const int multicast_filter_limit = 100; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. */ @@ -374,7 +374,7 @@ enum pcistuff { /* array of board data directly indexed by pci_tbl[x].driver_data */ -static struct { +static const struct { const char *name; unsigned long flags; } natsemi_pci_info[] __devinitdata = { diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index d11821dd86e..e3ebb5803b0 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -117,7 +117,7 @@ enum ne2k_pci_chipsets { }; -static struct { +static const struct { char *name; int flags; } pci_clone_list[] __devinitdata = { diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index b0c3b6ab626..f3924fb615b 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -651,7 +651,7 @@ static void FASTCALL(phy_intr(struct net_device *ndev)); static void fastcall phy_intr(struct net_device *ndev) { struct ns83820 *dev = PRIV(ndev); - static char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" }; + static const char *speeds[] = { "10", "100", "1000", "1000(?)", "1000F" }; u32 cfg, new_cfg; u32 tbisr, tanar, tanlpar; int speed, fullduplex, newlinkstate; diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 48774efeec7..ce90becb8bd 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -341,7 +341,7 @@ static void tc574_detach(struct pcmcia_device *p_dev) #define CS_CHECK(fn, ret) \ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) -static char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; +static const char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; static void tc574_config(dev_link_t *link) { diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index 1c3c9c666f7..576b2bf4692 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -115,7 +115,7 @@ struct el3_private { spinlock_t lock; }; -static char *if_names[] = { "auto", "10baseT", "10base2", "AUI" }; +static const char *if_names[] = { "auto", "10baseT", "10base2", "AUI" }; /*====================================================================*/ diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 28fe2fb4d6c..b7ac14ba887 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -309,7 +309,7 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) static int mfc_try_io_port(dev_link_t *link) { int i, ret; - static kio_addr_t serial_base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; + static const kio_addr_t serial_base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; for (i = 0; i < 5; i++) { link->io.BasePort2 = serial_base[i]; diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 4a232254a49..787176c57fd 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -388,7 +388,7 @@ static char *version = DRV_NAME " " DRV_VERSION " (Roger C. Pao)"; #endif -static char *if_names[]={ +static const char *if_names[]={ "Auto", "10baseT", "BNC", }; diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index d85b758f3ef..a280cf65048 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -66,7 +66,7 @@ #define PCNET_RDC_TIMEOUT (2*HZ/100) /* Max wait in jiffies for Tx RDC */ -static char *if_names[] = { "auto", "10baseT", "10base2"}; +static const char *if_names[] = { "auto", "10baseT", "10base2"}; #ifdef PCMCIA_DEBUG static int pc_debug = PCMCIA_DEBUG; diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index 0122415dfee..8839c4faafd 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -59,7 +59,7 @@ /*====================================================================*/ -static char *if_names[] = { "auto", "10baseT", "10base2"}; +static const char *if_names[] = { "auto", "10baseT", "10base2"}; /* Module parameters */ @@ -777,7 +777,7 @@ free_cfg_mem: static int osi_config(dev_link_t *link) { struct net_device *dev = link->priv; - static kio_addr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; + static const kio_addr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; int i, j; link->conf.Attributes |= CONF_ENABLE_SPKR; diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index 593d8adee89..eed496803fe 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -208,7 +208,7 @@ enum xirc_cmd { /* Commands */ #define XIRCREG45_REV 15 /* Revision Register (rd) */ #define XIRCREG50_IA 8 /* Individual Address (8-13) */ -static char *if_names[] = { "Auto", "10BaseT", "10Base2", "AUI", "100BaseT" }; +static const char *if_names[] = { "Auto", "10BaseT", "10Base2", "AUI", "100BaseT" }; /**************** * All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 8f6cf8c896a..7e900572eaf 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -26,7 +26,7 @@ #define DRV_RELDATE "01.Nov.2005" #define PFX DRV_NAME ": " -static const char *version = +static const char * const version = DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n"; #include @@ -109,7 +109,7 @@ static int rx_copybreak = 200; * table to translate option values from tulip * to internal options */ -static unsigned char options_mapping[] = { +static const unsigned char options_mapping[] = { PCNET32_PORT_ASEL, /* 0 Auto-select */ PCNET32_PORT_AUI, /* 1 BNC/AUI */ PCNET32_PORT_AUI, /* 2 AUI/BNC */ @@ -733,7 +733,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t *data1) int rc; /* return code */ int size; /* size of packets */ unsigned char *packet; /* source packet data */ - static int data_len = 60; /* length of source packets */ + static const int data_len = 60; /* length of source packets */ unsigned long flags; unsigned long ticks; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 1474b7c5ac0..33cec2dab94 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -132,7 +132,7 @@ struct phy_setting { }; /* A mapping of all SUPPORTED settings to speed/duplex */ -static struct phy_setting settings[] = { +static const struct phy_setting settings[] = { { .speed = 10000, .duplex = DUPLEX_FULL, diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 87ee3271b17..d4449d6d1fe 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -123,7 +123,7 @@ static const char version[] = "NET3 PLIP version 2.4-parport gniibe@mri.co.jp\n" #ifndef NET_DEBUG #define NET_DEBUG 1 #endif -static unsigned int net_debug = NET_DEBUG; +static const unsigned int net_debug = NET_DEBUG; #define ENABLE(irq) if (irq != -1) enable_irq(irq) #define DISABLE(irq) if (irq != -1) disable_irq(irq) @@ -351,7 +351,7 @@ static int plip_bh_timeout_error(struct net_device *dev, struct net_local *nl, typedef int (*plip_func)(struct net_device *dev, struct net_local *nl, struct plip_local *snd, struct plip_local *rcv); -static plip_func connection_state_table[] = +static const plip_func connection_state_table[] = { plip_none, plip_receive_packet, diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index 33cb8254e79..33255fe8031 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -108,7 +108,7 @@ static void ppp_print_hex (register __u8 * out, const __u8 * in, int count) { register __u8 next_ch; - static char hex[] = "0123456789ABCDEF"; + static const char hex[] = "0123456789ABCDEF"; while (count-- > 0) { next_ch = *in++; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 8cc0d0bbdf5..0ad3310290f 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -113,11 +113,11 @@ static int media[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; static int num_media = 0; /* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; +static const int max_interrupt_work = 20; /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). The RTL chips use a 64 element hash table based on the Ethernet CRC. */ -static int multicast_filter_limit = 32; +static const int multicast_filter_limit = 32; /* MAC address length */ #define MAC_ADDR_LEN 6 diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 49b597cbc19..a49ff17e1b8 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -214,7 +214,7 @@ static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) #define SWITCH_SIGN 0xA5A5A5A5A5A5A5A5ULL #define END_SIGN 0x0 -static u64 herc_act_dtx_cfg[] = { +static const u64 herc_act_dtx_cfg[] = { /* Set address */ 0x8000051536750000ULL, 0x80000515367500E0ULL, /* Write data */ @@ -235,7 +235,7 @@ static u64 herc_act_dtx_cfg[] = { END_SIGN }; -static u64 xena_mdio_cfg[] = { +static const u64 xena_mdio_cfg[] = { /* Reset PMA PLL */ 0xC001010000000000ULL, 0xC0010100000000E0ULL, 0xC0010100008000E4ULL, @@ -245,7 +245,7 @@ static u64 xena_mdio_cfg[] = { END_SIGN }; -static u64 xena_dtx_cfg[] = { +static const u64 xena_dtx_cfg[] = { 0x8000051500000000ULL, 0x80000515000000E0ULL, 0x80000515D93500E4ULL, 0x8001051500000000ULL, 0x80010515000000E0ULL, 0x80010515001E00E4ULL, @@ -273,7 +273,7 @@ static u64 xena_dtx_cfg[] = { * Constants for Fixing the MacAddress problem seen mostly on * Alpha machines. */ -static u64 fix_mac[] = { +static const u64 fix_mac[] = { 0x0060000000000000ULL, 0x0060600000000000ULL, 0x0040600000000000ULL, 0x0000600000000000ULL, 0x0020600000000000ULL, 0x0060600000000000ULL, diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index 76139478c3d..66cf226c4ee 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -59,7 +59,7 @@ static char version[] = "sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)\n"; #ifdef SB1000_DEBUG static int sb1000_debug = SB1000_DEBUG; #else -static int sb1000_debug = 1; +static const int sb1000_debug = 1; #endif static const int SB1000_IO_EXTENT = 8; diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index ed4bc91638d..31dd3f036fa 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -366,7 +366,7 @@ static const u32 sis190_intr_mask = * Maximum number of multicast addresses to filter (vs. Rx-all-multicast). * The chips use a 64 element hash table based on the Ethernet CRC. */ -static int multicast_filter_limit = 32; +static const int multicast_filter_limit = 32; static void __mdio_cmd(void __iomem *ioaddr, u32 ctl) { diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 7a952fe60be..a1cb07cdb60 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -100,7 +100,7 @@ enum { SIS_900 = 0, SIS_7016 }; -static char * card_names[] = { +static const char * card_names[] = { "SiS 900 PCI Fast Ethernet", "SiS 7016 PCI Fast Ethernet" }; @@ -115,7 +115,7 @@ MODULE_DEVICE_TABLE (pci, sis900_pci_tbl); static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex); -static struct mii_chip_info { +static const struct mii_chip_info { const char * name; u16 phy_id0; u16 phy_id1; @@ -400,7 +400,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, void *ring_space; long ioaddr; int i, ret; - char *card_name = card_names[pci_id->driver_data]; + const char *card_name = card_names[pci_id->driver_data]; const char *dev_name = pci_name(pci_dev); /* when built into the kernel, we only print version if device is found */ @@ -1275,7 +1275,7 @@ static void sis900_timer(unsigned long data) struct net_device *net_dev = (struct net_device *)data; struct sis900_private *sis_priv = net_dev->priv; struct mii_phy *mii_phy = sis_priv->mii; - static int next_tick = 5*HZ; + static const int next_tick = 5*HZ; u16 status; if (!sis_priv->autong_complete){ diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c index a2ed47f1cc7..a4b2b6975d6 100644 --- a/drivers/net/skfp/fplustm.c +++ b/drivers/net/skfp/fplustm.c @@ -89,21 +89,21 @@ static const u_short my_sagp = 0xffff ; /* short group address (n.u.) */ /* * useful interrupt bits */ -static int mac_imsk1u = FM_STXABRS | FM_STXABRA0 | FM_SXMTABT ; -static int mac_imsk1l = FM_SQLCKS | FM_SQLCKA0 | FM_SPCEPDS | FM_SPCEPDA0| +static const int mac_imsk1u = FM_STXABRS | FM_STXABRA0 | FM_SXMTABT ; +static const int mac_imsk1l = FM_SQLCKS | FM_SQLCKA0 | FM_SPCEPDS | FM_SPCEPDA0| FM_STBURS | FM_STBURA0 ; /* delete FM_SRBFL after tests */ -static int mac_imsk2u = FM_SERRSF | FM_SNFSLD | FM_SRCVOVR | FM_SRBFL | +static const int mac_imsk2u = FM_SERRSF | FM_SNFSLD | FM_SRCVOVR | FM_SRBFL | FM_SMYCLM ; -static int mac_imsk2l = FM_STRTEXR | FM_SDUPCLM | FM_SFRMCTR | +static const int mac_imsk2l = FM_STRTEXR | FM_SDUPCLM | FM_SFRMCTR | FM_SERRCTR | FM_SLSTCTR | FM_STRTEXP | FM_SMULTDA | FM_SRNGOP ; -static int mac_imsk3u = FM_SRCVOVR2 | FM_SRBFL2 ; -static int mac_imsk3l = FM_SRPERRQ2 | FM_SRPERRQ1 ; +static const int mac_imsk3u = FM_SRCVOVR2 | FM_SRBFL2 ; +static const int mac_imsk3l = FM_SRPERRQ2 | FM_SRPERRQ1 ; -static int mac_beacon_imsk2u = FM_SOTRBEC | FM_SMYBEC | FM_SBEC | +static const int mac_beacon_imsk2u = FM_SOTRBEC | FM_SMYBEC | FM_SBEC | FM_SLOCLM | FM_SHICLM | FM_SMYCLM | FM_SCLM ; diff --git a/drivers/net/skfp/pcmplc.c b/drivers/net/skfp/pcmplc.c index cd0aa4c151b..74e129f3ce9 100644 --- a/drivers/net/skfp/pcmplc.c +++ b/drivers/net/skfp/pcmplc.c @@ -186,7 +186,7 @@ static const struct plt { * Do we need the EBUF error during signaling, too, to detect SUPERNET_3 * PLL bug? */ -static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | +static const int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR; #else /* SUPERNET_3 */ /* @@ -195,7 +195,7 @@ static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | PL_PCM_ENABLED | PL_SELF_TEST ; #endif /* SUPERNET_3 */ -static int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | +static const int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR; /* external functions */ diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index 4b5ed2c6317..c7fb6133047 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -67,7 +67,7 @@ /* each new release!!! */ #define VERSION "2.07" -static const char *boot_msg = +static const char * const boot_msg = "SysKonnect FDDI PCI Adapter driver v" VERSION " for\n" " SK-55xx/SK-58xx adapters (SK-NET FDDI-FP/UP/LP)"; diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index d167deda9a5..a6bf5728fed 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -201,7 +201,7 @@ static int max_interrupt_work = 20; static int mtu; /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). The Starfire has a 512 element hash table based on the Ethernet CRC. */ -static int multicast_filter_limit = 512; +static const int multicast_filter_limit = 512; /* Whether to do TCP/UDP checksums in hardware */ static int enable_hw_cksum = 1; @@ -463,7 +463,7 @@ static struct pci_device_id starfire_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, starfire_pci_tbl); /* A chip capabilities table, matching the CH_xxx entries in xxx_pci_tbl[] above. */ -static struct chip_info { +static const struct chip_info { const char *name; int drv_flags; } netdrv_tbl[] __devinitdata = { diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index 0ab9c38b4a3..059141814fe 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -106,7 +106,7 @@ static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */ /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). Typical is a 64 element hash table based on the Ethernet CRC. */ -static int multicast_filter_limit = 32; +static const int multicast_filter_limit = 32; /* Set the copy breakpoint for the copy-only-tiny-frames scheme. Setting to > 1518 effectively disables this feature. @@ -298,7 +298,7 @@ enum { struct pci_id_info { const char *name; }; -static struct pci_id_info pci_id_tbl[] = { +static const struct pci_id_info pci_id_tbl[] = { {"D-Link DFE-550TX FAST Ethernet Adapter"}, {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter"}, {"D-Link DFE-580TX 4 port Server Adapter"}, diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c index d3ddb41d6e5..cb0aba95d4e 100644 --- a/drivers/net/sungem_phy.c +++ b/drivers/net/sungem_phy.c @@ -39,7 +39,7 @@ #include "sungem_phy.h" /* Link modes of the BCM5400 PHY */ -static int phy_BCM5400_link_table[8][3] = { +static const int phy_BCM5400_link_table[8][3] = { { 0, 0, 0 }, /* No link */ { 0, 0, 0 }, /* 10BT Half Duplex */ { 1, 0, 0 }, /* 10BT Full Duplex */ diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e8e92c853e8..83ff5994a8d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7785,7 +7785,7 @@ static int tg3_test_link(struct tg3 *tp) } /* Only test the commonly used registers */ -static int tg3_test_registers(struct tg3 *tp) +static const int tg3_test_registers(struct tg3 *tp) { int i, is_5705; u32 offset, read_mask, write_mask, val, save_val, read_val; @@ -7999,7 +7999,7 @@ out: static int tg3_do_mem_test(struct tg3 *tp, u32 offset, u32 len) { - static u32 test_pattern[] = { 0x00000000, 0xffffffff, 0xaa55a55a }; + static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0xaa55a55a }; int i; u32 j; diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 4c76cb794bf..cde35dd8790 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -178,7 +178,7 @@ enum typhoon_cards { }; /* directly indexed by enum typhoon_cards, above */ -static struct typhoon_card_info typhoon_card_info[] __devinitdata = { +static const struct typhoon_card_info typhoon_card_info[] __devinitdata = { { "3Com Typhoon (3C990-TX)", TYPHOON_CRYPTO_NONE}, { "3Com Typhoon (3CR990-TX-95)", diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 1c2506535f7..75d56bfef0e 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -69,8 +69,8 @@ static int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */ static int dma_ctrl = 0x00CAC277; /* Override when loading module! */ static int fifo_cfg = 0x0028; #else -static int dma_ctrl = 0x004A0263; /* Constrained by errata */ -static int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */ +static const int dma_ctrl = 0x004A0263; /* Constrained by errata */ +static const int fifo_cfg = 0x0020; /* Bypass external Tx FIFO. */ #endif /* Set the copy breakpoint for the copy-only-tiny-frames scheme. @@ -266,7 +266,7 @@ struct pci_id_info { int drv_flags; /* Driver use, intended as capability flags. */ }; -static struct pci_id_info pci_id_tbl[] = { +static const struct pci_id_info pci_id_tbl[] = { {"Yellowfin G-NIC Gigabit Ethernet", { 0x07021000, 0xffffffff}, PCI_IOTYPE, YELLOWFIN_SIZE, FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug | DontUseEeprom}, -- cgit v1.2.3 From c3cf560e35509634d72cf809074834d5ea23ab66 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 4 Mar 2006 17:07:57 +0100 Subject: [PATCH] remove obsolete sis900 documentation This documentation is mostly obsolete, and should therefore either be updated or removed (this patch does the latter). Signed-off-by: Adrian Bunk Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 11ca9f03b43..bdf294d2df2 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1613,11 +1613,7 @@ config SIS900 ---help--- This is a driver for the Fast Ethernet PCI network cards based on the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in - SiS 630 and SiS 540 chipsets. If you have one of those, say Y and - read the Ethernet-HOWTO, available at - . Please read - and comments at the - beginning of for more information. + SiS 630 and SiS 540 chipsets. This driver also supports AMD 79C901 HomePNA so that you can use your phone line as a network cable. -- cgit v1.2.3 From b27a16b7c4738ea16f6f0730caf382a3f57317bb Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 2 Feb 2006 00:00:01 +0000 Subject: [PATCH] natsemi: NAPI and a bugfix This patch converts the natsemi driver to use NAPI. It was originally based on one written by Harald Welte, though it has since been modified quite a bit, most extensively in order to remove the ability to disable NAPI since none of the other drivers seem to provide that functionality any more. Signed-off-by: Mark Brown Signed-off-by: Jeff Garzik --- drivers/net/natsemi.c | 146 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 97 insertions(+), 49 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 01920648fc3..e363f9bb35e 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -3,6 +3,7 @@ Written/copyright 1999-2001 by Donald Becker. Portions copyright (c) 2001,2002 Sun Microsystems (thockin@sun.com) Portions copyright 2001,2002 Manfred Spraul (manfred@colorfullife.com) + Portions copyright 2004 Harald Welte This software may be used and distributed according to the terms of the GNU General Public License (GPL), incorporated herein by reference. @@ -135,8 +136,6 @@ TODO: * big endian support with CFG:BEM instead of cpu_to_le32 - * support for an external PHY - * NAPI */ #include @@ -160,6 +159,7 @@ #include #include #include +#include #include /* Processor type for cache alignment. */ #include #include @@ -183,8 +183,6 @@ NETIF_MSG_TX_ERR) static int debug = -1; -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; static int mtu; /* Maximum number of multicast addresses to filter (vs. rx-all-multicast). @@ -251,14 +249,11 @@ MODULE_AUTHOR("Donald Becker "); MODULE_DESCRIPTION("National Semiconductor DP8381x series PCI Ethernet driver"); MODULE_LICENSE("GPL"); -module_param(max_interrupt_work, int, 0); module_param(mtu, int, 0); module_param(debug, int, 0); module_param(rx_copybreak, int, 0); module_param_array(options, int, NULL, 0); module_param_array(full_duplex, int, NULL, 0); -MODULE_PARM_DESC(max_interrupt_work, - "DP8381x maximum events handled per interrupt"); MODULE_PARM_DESC(mtu, "DP8381x MTU (all boards)"); MODULE_PARM_DESC(debug, "DP8381x default debug level"); MODULE_PARM_DESC(rx_copybreak, @@ -691,6 +686,8 @@ struct netdev_private { /* Based on MTU+slack. */ unsigned int rx_buf_sz; int oom; + /* Interrupt status */ + u32 intr_status; /* Do not touch the nic registers */ int hands_off; /* external phy that is used: only valid if dev->if_port != PORT_TP */ @@ -748,7 +745,8 @@ static void init_registers(struct net_device *dev); static int start_tx(struct sk_buff *skb, struct net_device *dev); static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs); static void netdev_error(struct net_device *dev, int intr_status); -static void netdev_rx(struct net_device *dev); +static int natsemi_poll(struct net_device *dev, int *budget); +static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do); static void netdev_tx_done(struct net_device *dev); static int natsemi_change_mtu(struct net_device *dev, int new_mtu); #ifdef CONFIG_NET_POLL_CONTROLLER @@ -776,6 +774,18 @@ static inline void __iomem *ns_ioaddr(struct net_device *dev) return (void __iomem *) dev->base_addr; } +static inline void natsemi_irq_enable(struct net_device *dev) +{ + writel(1, ns_ioaddr(dev) + IntrEnable); + readl(ns_ioaddr(dev) + IntrEnable); +} + +static inline void natsemi_irq_disable(struct net_device *dev) +{ + writel(0, ns_ioaddr(dev) + IntrEnable); + readl(ns_ioaddr(dev) + IntrEnable); +} + static void move_int_phy(struct net_device *dev, int addr) { struct netdev_private *np = netdev_priv(dev); @@ -879,6 +889,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, spin_lock_init(&np->lock); np->msg_enable = (debug >= 0) ? (1<hands_off = 0; + np->intr_status = 0; /* Initial port: * - If the nic was configured to use an external phy and if find_mii @@ -932,6 +943,9 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, dev->do_ioctl = &netdev_ioctl; dev->tx_timeout = &tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; + dev->poll = natsemi_poll; + dev->weight = 64; + #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = &natsemi_poll_controller; #endif @@ -2158,68 +2172,92 @@ static void netdev_tx_done(struct net_device *dev) } } -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ +/* The interrupt handler doesn't actually handle interrupts itself, it + * schedules a NAPI poll if there is anything to do. */ static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs) { struct net_device *dev = dev_instance; struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); - int boguscnt = max_interrupt_work; - unsigned int handled = 0; if (np->hands_off) return IRQ_NONE; - do { - /* Reading automatically acknowledges all int sources. */ - u32 intr_status = readl(ioaddr + IntrStatus); + + /* Reading automatically acknowledges. */ + np->intr_status = readl(ioaddr + IntrStatus); - if (netif_msg_intr(np)) - printk(KERN_DEBUG - "%s: Interrupt, status %#08x, mask %#08x.\n", - dev->name, intr_status, - readl(ioaddr + IntrMask)); + if (netif_msg_intr(np)) + printk(KERN_DEBUG + "%s: Interrupt, status %#08x, mask %#08x.\n", + dev->name, np->intr_status, + readl(ioaddr + IntrMask)); - if (intr_status == 0) - break; - handled = 1; + if (!np->intr_status) + return IRQ_NONE; - if (intr_status & - (IntrRxDone | IntrRxIntr | RxStatusFIFOOver | - IntrRxErr | IntrRxOverrun)) { - netdev_rx(dev); - } + prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]); + + if (netif_rx_schedule_prep(dev)) { + /* Disable interrupts and register for poll */ + natsemi_irq_disable(dev); + __netif_rx_schedule(dev); + } + return IRQ_HANDLED; +} + +/* This is the NAPI poll routine. As well as the standard RX handling + * it also handles all other interrupts that the chip might raise. + */ +static int natsemi_poll(struct net_device *dev, int *budget) +{ + struct netdev_private *np = netdev_priv(dev); + void __iomem * ioaddr = ns_ioaddr(dev); - if (intr_status & - (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) { + int work_to_do = min(*budget, dev->quota); + int work_done = 0; + + do { + if (np->intr_status & + (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) { spin_lock(&np->lock); netdev_tx_done(dev); spin_unlock(&np->lock); } /* Abnormal error summary/uncommon events handlers. */ - if (intr_status & IntrAbnormalSummary) - netdev_error(dev, intr_status); - - if (--boguscnt < 0) { - if (netif_msg_intr(np)) - printk(KERN_WARNING - "%s: Too much work at interrupt, " - "status=%#08x.\n", - dev->name, intr_status); - break; + if (np->intr_status & IntrAbnormalSummary) + netdev_error(dev, np->intr_status); + + if (np->intr_status & + (IntrRxDone | IntrRxIntr | RxStatusFIFOOver | + IntrRxErr | IntrRxOverrun)) { + netdev_rx(dev, &work_done, work_to_do); } - } while (1); + + *budget -= work_done; + dev->quota -= work_done; - if (netif_msg_intr(np)) - printk(KERN_DEBUG "%s: exiting interrupt.\n", dev->name); + if (work_done >= work_to_do) + return 1; + + np->intr_status = readl(ioaddr + IntrStatus); + } while (np->intr_status); - return IRQ_RETVAL(handled); + netif_rx_complete(dev); + + /* Reenable interrupts providing nothing is trying to shut + * the chip down. */ + spin_lock(&np->lock); + if (!np->hands_off && netif_running(dev)) + natsemi_irq_enable(dev); + spin_unlock(&np->lock); + + return 0; } /* This routine is logically part of the interrupt handler, but separated for clarity and better register allocation. */ -static void netdev_rx(struct net_device *dev) +static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do) { struct netdev_private *np = netdev_priv(dev); int entry = np->cur_rx % RX_RING_SIZE; @@ -2237,6 +2275,12 @@ static void netdev_rx(struct net_device *dev) entry, desc_status); if (--boguscnt < 0) break; + + if (*work_done >= work_to_do) + break; + + (*work_done)++; + pkt_len = (desc_status & DescSizeMask) - 4; if ((desc_status&(DescMore|DescPktOK|DescRxLong)) != DescPktOK){ if (desc_status & DescMore) { @@ -2293,7 +2337,7 @@ static void netdev_rx(struct net_device *dev) np->rx_skbuff[entry] = NULL; } skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); + netif_receive_skb(skb); dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += pkt_len; @@ -3074,9 +3118,7 @@ static int netdev_close(struct net_device *dev) del_timer_sync(&np->timer); disable_irq(dev->irq); spin_lock_irq(&np->lock); - /* Disable interrupts, and flush posted writes */ - writel(0, ioaddr + IntrEnable); - readl(ioaddr + IntrEnable); + natsemi_irq_disable(dev); np->hands_off = 1; spin_unlock_irq(&np->lock); enable_irq(dev->irq); @@ -3158,6 +3200,9 @@ static void __devexit natsemi_remove1 (struct pci_dev *pdev) * * netdev_timer: timer stopped by natsemi_suspend. * * intr_handler: doesn't acquire the spinlock. suspend calls * disable_irq() to enforce synchronization. + * * natsemi_poll: checks before reenabling interrupts. suspend + * sets hands_off, disables interrupts and then waits with + * netif_poll_disable(). * * Interrupts must be disabled, otherwise hands_off can cause irq storms. */ @@ -3183,6 +3228,8 @@ static int natsemi_suspend (struct pci_dev *pdev, pm_message_t state) spin_unlock_irq(&np->lock); enable_irq(dev->irq); + netif_poll_disable(dev); + /* Update the error counts. */ __get_stats(dev); @@ -3235,6 +3282,7 @@ static int natsemi_resume (struct pci_dev *pdev) mod_timer(&np->timer, jiffies + 1*HZ); } netif_device_attach(dev); + netif_poll_enable(dev); out: rtnl_unlock(); return 0; -- cgit v1.2.3 From e72fd96e8ee3ff4dd80757172a4fe49bd92fea9c Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Thu, 2 Feb 2006 00:00:02 +0000 Subject: [PATCH] natsemi: NAPI and a bugfix As documented in National application note 1287 the RX state machine on the natsemi chip can lock up under some conditions (mostly related to heavy load). When this happens a series of bogus packets are reported by the chip including some oversized frames prior to the final lockup. This patch implements the fix from the application note: when an oversized packet is reported it resets the RX state machine, dropping any currently pending packets. Signed-off-by: Mark Brown Signed-off-by: Jeff Garzik --- drivers/net/natsemi.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index e363f9bb35e..8d4999837b6 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -1498,6 +1498,31 @@ static void natsemi_reset(struct net_device *dev) writel(rfcr, ioaddr + RxFilterAddr); } +static void reset_rx(struct net_device *dev) +{ + int i; + struct netdev_private *np = netdev_priv(dev); + void __iomem *ioaddr = ns_ioaddr(dev); + + np->intr_status &= ~RxResetDone; + + writel(RxReset, ioaddr + ChipCmd); + + for (i=0;iintr_status |= readl(ioaddr + IntrStatus); + if (np->intr_status & RxResetDone) + break; + udelay(15); + } + if (i==NATSEMI_HW_TIMEOUT) { + printk(KERN_WARNING "%s: RX reset did not complete in %d usec.\n", + dev->name, i*15); + } else if (netif_msg_hw(np)) { + printk(KERN_WARNING "%s: RX reset took %d usec.\n", + dev->name, i*15); + } +} + static void natsemi_reload_eeprom(struct net_device *dev) { struct netdev_private *np = netdev_priv(dev); @@ -2292,6 +2317,23 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do) "status %#08x.\n", dev->name, np->cur_rx, desc_status); np->stats.rx_length_errors++; + + /* The RX state machine has probably + * locked up beneath us. Follow the + * reset procedure documented in + * AN-1287. */ + + spin_lock_irq(&np->lock); + reset_rx(dev); + reinit_rx(dev); + writel(np->ring_dma, ioaddr + RxRingPtr); + check_link(dev); + spin_unlock_irq(&np->lock); + + /* We'll enable RX on exit from this + * function. */ + break; + } else { /* There was an error. */ np->stats.rx_errors++; -- cgit v1.2.3 From ad8c48ad3bbef078616ed4d2652d362dfd962f09 Mon Sep 17 00:00:00 2001 From: "Catalin(ux aka Dino) BOIE" Date: Sat, 4 Mar 2006 12:18:59 -0500 Subject: Fix io ordering problems in e100 Checking e100.c code against Documentation/io_ordering.txt I found the following problem: spin_lock_irq... write spin-unlock e100_write_flush The attached patch fix the code like this: spin_lock_irq... write e100_write_flush spin-unlock Signed-off-by: Catalin BOIE Signed-off-by: Jeff Garzik --- drivers/net/e100.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 24253c807e5..ed13f72ef8e 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -598,8 +598,8 @@ static void e100_enable_irq(struct nic *nic) spin_lock_irqsave(&nic->cmd_lock, flags); writeb(irq_mask_none, &nic->csr->scb.cmd_hi); - spin_unlock_irqrestore(&nic->cmd_lock, flags); e100_write_flush(nic); + spin_unlock_irqrestore(&nic->cmd_lock, flags); } static void e100_disable_irq(struct nic *nic) @@ -608,8 +608,8 @@ static void e100_disable_irq(struct nic *nic) spin_lock_irqsave(&nic->cmd_lock, flags); writeb(irq_mask_all, &nic->csr->scb.cmd_hi); - spin_unlock_irqrestore(&nic->cmd_lock, flags); e100_write_flush(nic); + spin_unlock_irqrestore(&nic->cmd_lock, flags); } static void e100_hw_reset(struct nic *nic) @@ -1582,8 +1582,8 @@ static void e100_watchdog(unsigned long data) * interrupt mask bit and the SW Interrupt generation bit */ spin_lock_irq(&nic->cmd_lock); writeb(readb(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi); - spin_unlock_irq(&nic->cmd_lock); e100_write_flush(nic); + spin_unlock_irq(&nic->cmd_lock); e100_update_stats(nic); e100_adjust_adaptive_ifs(nic, cmd.speed, cmd.duplex); -- cgit v1.2.3 From cb764326dff0ee51aca0d450e1a292de65661055 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Wed, 8 Mar 2006 17:24:12 -0800 Subject: e1000: Fix mii-tool access to setting speed and duplex Paul Rolland reported that e1000 was having a hard time using mii-tool to set speed and duplex. This patch fixes the issue on both newer hardware as well as fixing the code issue that originally caused the problem. Signed-off-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher --- drivers/net/e1000/e1000_main.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 9adaf5fa9d4..5f7e5c80820 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -4171,7 +4171,7 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) spin_unlock_irqrestore(&adapter->stats_lock, flags); return -EIO; } - if (adapter->hw.phy_type == e1000_phy_m88) { + if (adapter->hw.phy_type == e1000_media_type_copper) { switch (data->reg_num) { case PHY_CTRL: if (mii_reg & MII_CR_POWER_DOWN) @@ -4187,8 +4187,8 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) else spddplx = SPEED_10; spddplx += (mii_reg & 0x100) - ? FULL_DUPLEX : - HALF_DUPLEX; + ? DUPLEX_FULL : + DUPLEX_HALF; retval = e1000_set_spd_dplx(adapter, spddplx); if (retval) { -- cgit v1.2.3 From 827700866ad0996e8c0f5ce75d1c01ae9b034cd6 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 8 Mar 2006 00:06:30 -0800 Subject: [PATCH] CONFIG_FORCEDETH updates This patch contains the following possible updates: - let FORCEDETH no longer depend on EXPERIMENTAL - remove the "Reverse Engineered" from the option text: for the user it's important which hardware the driver supports, not how it was developed Signed-off-by: Adrian Bunk Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index d4d8e5f9ebf..e0b11095b9d 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1372,8 +1372,8 @@ config B44 called b44. config FORCEDETH - tristate "Reverse Engineered nForce Ethernet support (EXPERIMENTAL)" - depends on NET_PCI && PCI && EXPERIMENTAL + tristate "nForce Ethernet support" + depends on NET_PCI && PCI help If you have a network (Ethernet) controller of this type, say Y and read the Ethernet-HOWTO, available from -- cgit v1.2.3 From 60a89ff6d2681029b3d46b5d23dccf2903a254b4 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Wed, 8 Mar 2006 00:06:28 -0800 Subject: [PATCH] 3c509: use proper suspend/resume API Convert 3c509 driver to use proper suspend/resume API instead of the deprecated pm_register/pm_unregister. Signed-off-by: Pekka Enberg Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/3c509.c | 70 ++++++++++++++++++----------------------------------- 1 file changed, 23 insertions(+), 47 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index 830528dce0c..dc845f36fe4 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -100,6 +100,10 @@ static int max_interrupt_work = 10; static char versionA[] __initdata = DRV_NAME ".c:" DRV_VERSION " " DRV_RELDATE " becker@scyld.com\n"; static char versionB[] __initdata = "http://www.scyld.com/network/3c509.html\n"; +#if defined(CONFIG_PM) && (defined(CONFIG_MCA) || defined(CONFIG_EISA)) +#define EL3_SUSPEND +#endif + #ifdef EL3_DEBUG static int el3_debug = EL3_DEBUG; #else @@ -174,9 +178,6 @@ struct el3_private { /* skb send-queue */ int head, size; struct sk_buff *queue[SKB_QUEUE_SIZE]; -#ifdef CONFIG_PM_LEGACY - struct pm_dev *pmdev; -#endif enum { EL3_MCA, EL3_PNP, @@ -201,11 +202,15 @@ static void el3_tx_timeout (struct net_device *dev); static void el3_down(struct net_device *dev); static void el3_up(struct net_device *dev); static struct ethtool_ops ethtool_ops; -#ifdef CONFIG_PM_LEGACY -static int el3_suspend(struct pm_dev *pdev); -static int el3_resume(struct pm_dev *pdev); -static int el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data); +#ifdef EL3_SUSPEND +static int el3_suspend(struct device *, pm_message_t); +static int el3_resume(struct device *); +#else +#define el3_suspend NULL +#define el3_resume NULL #endif + + /* generic device remove for all device types */ #if defined(CONFIG_EISA) || defined(CONFIG_MCA) static int el3_device_remove (struct device *device); @@ -229,7 +234,9 @@ static struct eisa_driver el3_eisa_driver = { .driver = { .name = "3c509", .probe = el3_eisa_probe, - .remove = __devexit_p (el3_device_remove) + .remove = __devexit_p (el3_device_remove), + .suspend = el3_suspend, + .resume = el3_resume, } }; #endif @@ -262,6 +269,8 @@ static struct mca_driver el3_mca_driver = { .bus = &mca_bus_type, .probe = el3_mca_probe, .remove = __devexit_p(el3_device_remove), + .suspend = el3_suspend, + .resume = el3_resume, }, }; #endif /* CONFIG_MCA */ @@ -362,10 +371,6 @@ static void el3_common_remove (struct net_device *dev) struct el3_private *lp = netdev_priv(dev); (void) lp; /* Keep gcc quiet... */ -#ifdef CONFIG_PM_LEGACY - if (lp->pmdev) - pm_unregister(lp->pmdev); -#endif #if defined(__ISAPNP__) if (lp->type == EL3_PNP) pnp_device_detach(to_pnp_dev(lp->dev)); @@ -572,16 +577,6 @@ no_pnp: if (err) goto out1; -#ifdef CONFIG_PM_LEGACY - /* register power management */ - lp->pmdev = pm_register(PM_ISA_DEV, card_idx, el3_pm_callback); - if (lp->pmdev) { - struct pm_dev *p; - p = lp->pmdev; - p->data = (struct net_device *)dev; - } -#endif - el3_cards++; lp->next_dev = el3_root_dev; el3_root_dev = dev; @@ -1480,20 +1475,17 @@ el3_up(struct net_device *dev) } /* Power Management support functions */ -#ifdef CONFIG_PM_LEGACY +#ifdef EL3_SUSPEND static int -el3_suspend(struct pm_dev *pdev) +el3_suspend(struct device *pdev, pm_message_t state) { unsigned long flags; struct net_device *dev; struct el3_private *lp; int ioaddr; - if (!pdev && !pdev->data) - return -EINVAL; - - dev = (struct net_device *)pdev->data; + dev = pdev->driver_data; lp = netdev_priv(dev); ioaddr = dev->base_addr; @@ -1510,17 +1502,14 @@ el3_suspend(struct pm_dev *pdev) } static int -el3_resume(struct pm_dev *pdev) +el3_resume(struct device *pdev) { unsigned long flags; struct net_device *dev; struct el3_private *lp; int ioaddr; - if (!pdev && !pdev->data) - return -EINVAL; - - dev = (struct net_device *)pdev->data; + dev = pdev->driver_data; lp = netdev_priv(dev); ioaddr = dev->base_addr; @@ -1536,20 +1525,7 @@ el3_resume(struct pm_dev *pdev) return 0; } -static int -el3_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data) -{ - switch (rqst) { - case PM_SUSPEND: - return el3_suspend(pdev); - - case PM_RESUME: - return el3_resume(pdev); - } - return 0; -} - -#endif /* CONFIG_PM_LEGACY */ +#endif /* EL3_SUSPEND */ /* Parameters that may be passed into the module. */ static int debug = -1; -- cgit v1.2.3 From a4d4d5181d043ea835c15da6c85a5bbecbaded6e Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 8 Mar 2006 11:49:31 +0000 Subject: [PATCH] Sparse: Cleanup sgiseeq sparse warnings. o Make sgiseeq_dump_rings static. o Delete unused sgiseeq_my_reset. o Move DEBUG define to beginning where it's easier to spot and will be seen by as well. o Use NULL for pointer initialization. Signed-off-by: Ralf Baechle Signed-off-by: Jeff Garzik --- drivers/net/sgiseeq.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index a4614df38a9..f95a5b0223f 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -3,6 +3,9 @@ * * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) */ + +#undef DEBUG + #include #include #include @@ -59,8 +62,6 @@ static char *sgiseeqstr = "SGI Seeq8003"; sp->tx_old + (SEEQ_TX_BUFFERS - 1) - sp->tx_new : \ sp->tx_old - sp->tx_new - 1) -#define DEBUG - struct sgiseeq_rx_desc { volatile struct hpc_dma_desc rdma; volatile signed int buf_vaddr; @@ -209,7 +210,7 @@ static int seeq_init_ring(struct net_device *dev) static struct sgiseeq_private *gpriv; static struct net_device *gdev; -void sgiseeq_dump_rings(void) +static void sgiseeq_dump_rings(void) { static int once; struct sgiseeq_rx_desc *r = gpriv->rx_desc; @@ -311,9 +312,9 @@ static inline void sgiseeq_rx(struct net_device *dev, struct sgiseeq_private *sp struct sgiseeq_regs *sregs) { struct sgiseeq_rx_desc *rd; - struct sk_buff *skb = 0; + struct sk_buff *skb = NULL; unsigned char pkt_status; - unsigned char *pkt_pointer = 0; + unsigned char *pkt_pointer = NULL; int len = 0; unsigned int orig_end = PREV_RX(sp->rx_new); @@ -515,12 +516,6 @@ static inline int sgiseeq_reset(struct net_device *dev) return 0; } -void sgiseeq_my_reset(void) -{ - printk("RESET!\n"); - sgiseeq_reset(gdev); -} - static int sgiseeq_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct sgiseeq_private *sp = netdev_priv(dev); -- cgit v1.2.3 From ded78e5e2cab0ec470cca7d34d7af742371bd476 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 10 Mar 2006 00:06:53 +0100 Subject: [PATCH] chelsio/espi.c:tricn_init(): remove dead code The Coverity checker spotted these two unused variables. Please check whether this patch is correct or whether they should be used. Signed-off-by: Adrian Bunk Signed-off-by: Jeff Garzik --- drivers/net/chelsio/espi.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/chelsio/espi.c b/drivers/net/chelsio/espi.c index e824acaf188..542e5e065c6 100644 --- a/drivers/net/chelsio/espi.c +++ b/drivers/net/chelsio/espi.c @@ -87,15 +87,9 @@ static int tricn_write(adapter_t *adapter, int bundle_addr, int module_addr, static int tricn_init(adapter_t *adapter) { int i = 0; - int sme = 1; int stat = 0; int timeout = 0; int is_ready = 0; - int dynamic_deskew = 0; - - if (dynamic_deskew) - sme = 0; - /* 1 */ timeout=1000; @@ -113,11 +107,9 @@ static int tricn_init(adapter_t *adapter) } /* 2 */ - if (sme) { - tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81); - tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81); - tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81); - } + tricn_write(adapter, 0, 0, 0, TRICN_CNFG, 0x81); + tricn_write(adapter, 0, 1, 0, TRICN_CNFG, 0x81); + tricn_write(adapter, 0, 2, 0, TRICN_CNFG, 0x81); for (i=1; i<= 8; i++) tricn_write(adapter, 0, 0, i, TRICN_CNFG, 0xf1); for (i=1; i<= 2; i++) tricn_write(adapter, 0, 1, i, TRICN_CNFG, 0xf1); for (i=1; i<= 3; i++) tricn_write(adapter, 0, 2, i, TRICN_CNFG, 0xe1); -- cgit v1.2.3 From 30dcbf29cc6d92d70fa262e79e84011fe6913bed Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 11 Mar 2006 17:51:39 -0800 Subject: [PATCH] drivers/net/e1000/: proper prototypes This patch moves prototypes of global variables and functions to a header file. Signed-off-by: Adrian Bunk Acked-by: John Ronciak Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000.h | 22 ++++++++++++++++++++++ drivers/net/e1000/e1000_ethtool.c | 13 ------------- drivers/net/e1000/e1000_main.c | 14 -------------- 3 files changed, 22 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 214468c35b4..281de41d030 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -339,4 +339,26 @@ struct e1000_adapter { boolean_t tso_force; #endif }; + + +/* e1000_main.c */ +extern char e1000_driver_name[]; +extern char e1000_driver_version[]; +int e1000_up(struct e1000_adapter *adapter); +void e1000_down(struct e1000_adapter *adapter); +void e1000_reset(struct e1000_adapter *adapter); +int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); +void e1000_free_all_tx_resources(struct e1000_adapter *adapter); +int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); +void e1000_free_all_rx_resources(struct e1000_adapter *adapter); +void e1000_update_stats(struct e1000_adapter *adapter); +int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); + +/* e1000_ethtool.c */ +void e1000_set_ethtool_ops(struct net_device *netdev); + +/* e1000_param.c */ +void e1000_check_options(struct e1000_adapter *adapter); + + #endif /* _E1000_H_ */ diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 44d39f1d829..ecccca35c6f 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c @@ -32,19 +32,6 @@ #include -extern char e1000_driver_name[]; -extern char e1000_driver_version[]; - -extern int e1000_up(struct e1000_adapter *adapter); -extern void e1000_down(struct e1000_adapter *adapter); -extern void e1000_reset(struct e1000_adapter *adapter); -extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); -extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); -extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); -extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter); -extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter); -extern void e1000_update_stats(struct e1000_adapter *adapter); - struct e1000_stats { char stat_string[ETH_GSTRING_LEN]; int sizeof_stat; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 34d77ed6aca..4400117eb6c 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -140,14 +140,6 @@ static struct pci_device_id e1000_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); -int e1000_up(struct e1000_adapter *adapter); -void e1000_down(struct e1000_adapter *adapter); -void e1000_reset(struct e1000_adapter *adapter); -int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx); -int e1000_setup_all_tx_resources(struct e1000_adapter *adapter); -int e1000_setup_all_rx_resources(struct e1000_adapter *adapter); -void e1000_free_all_tx_resources(struct e1000_adapter *adapter); -void e1000_free_all_rx_resources(struct e1000_adapter *adapter); static int e1000_setup_tx_resources(struct e1000_adapter *adapter, struct e1000_tx_ring *txdr); static int e1000_setup_rx_resources(struct e1000_adapter *adapter, @@ -156,7 +148,6 @@ static void e1000_free_tx_resources(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring); static void e1000_free_rx_resources(struct e1000_adapter *adapter, struct e1000_rx_ring *rx_ring); -void e1000_update_stats(struct e1000_adapter *adapter); /* Local Function Prototypes */ @@ -212,7 +203,6 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter, static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd); -void e1000_set_ethtool_ops(struct net_device *netdev); static void e1000_enter_82542_rst(struct e1000_adapter *adapter); static void e1000_leave_82542_rst(struct e1000_adapter *adapter); static void e1000_tx_timeout(struct net_device *dev); @@ -237,10 +227,6 @@ static void e1000_netpoll (struct net_device *netdev); #endif -/* Exported from other modules */ - -extern void e1000_check_options(struct e1000_adapter *adapter); - static struct pci_driver e1000_driver = { .name = e1000_driver_name, .id_table = e1000_pci_tbl, -- cgit v1.2.3 From aa49cdd93be6328113f0c146fc72be173d578d27 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Wed, 15 Mar 2006 10:55:24 -0800 Subject: e100: fix eeh on pseries during ethtool -t Olaf Hering reported a problem on pseries with e100 where ethtool -t would cause a bus error, and the e100 driver would stop working. Due to the new load ucode command the cb list must be allocated before calling e100_init_hw, so remove the call and just let e100_up take care of it. Signed-off-by: Jesse Brandeburg --- drivers/net/e100.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 24253c807e5..f57a85feda3 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2154,6 +2154,9 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode) msleep(10); + pci_dma_sync_single_for_cpu(nic->pdev, nic->rx_to_clean->dma_addr, + RFD_BUF_LEN, PCI_DMA_FROMDEVICE); + if(memcmp(nic->rx_to_clean->skb->data + sizeof(struct rfd), skb->data, ETH_DATA_LEN)) err = -EAGAIN; @@ -2161,8 +2164,8 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode) err_loopback_none: mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, 0); nic->loopback = lb_none; - e100_hw_init(nic); e100_clean_cbs(nic); + e100_hw_reset(nic); err_clean_rx: e100_rx_clean_list(nic); return err; -- cgit v1.2.3 From c3d7a3a4eb5e8f290d7b1d61430eed1ebedeb936 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 15 Mar 2006 14:26:28 -0800 Subject: [PATCH] e1000 endianness bugs return -E_NO_BIG_ENDIAN_TESTING; [E1000]: Fix 4 missed endianness conversions on RX descriptor fields. Signed-off-by: David S. Miller Signed-off-by: Jeff Garzik --- drivers/net/e1000/e1000_main.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 4c4db96d0b7..84dcca3776e 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -3710,7 +3710,7 @@ e1000_clean_rx_irq(struct e1000_adapter *adapter, e1000_rx_checksum(adapter, (uint32_t)(status) | ((uint32_t)(rx_desc->errors) << 24), - rx_desc->csum, skb); + le16_to_cpu(rx_desc->csum), skb); skb->protocol = eth_type_trans(skb, netdev); #ifdef CONFIG_E1000_NAPI @@ -3854,11 +3854,11 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, } e1000_rx_checksum(adapter, staterr, - rx_desc->wb.lower.hi_dword.csum_ip.csum, skb); + le16_to_cpu(rx_desc->wb.lower.hi_dword.csum_ip.csum), skb); skb->protocol = eth_type_trans(skb, netdev); if (likely(rx_desc->wb.upper.header_status & - E1000_RXDPS_HDRSTAT_HDRSP)) + cpu_to_le16(E1000_RXDPS_HDRSTAT_HDRSP))) adapter->rx_hdr_split++; #ifdef CONFIG_E1000_NAPI if (unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) { @@ -3884,7 +3884,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter, #endif next_desc: - rx_desc->wb.middle.status_error &= ~0xFF; + rx_desc->wb.middle.status_error &= cpu_to_le32(~0xFF); buffer_info->skb = NULL; /* return some buffers to hardware, one at a time is too slow */ -- cgit v1.2.3 From 232a347a444e687b5f8cf0f6485704db1c6024d3 Mon Sep 17 00:00:00 2001 From: Scott Bardone Date: Thu, 16 Mar 2006 19:20:40 -0500 Subject: [netdrvr] fix array overflows in Chelsio driver Adrian Bunk wrote: > The Coverity checker spotted the following two array overflows in > drivers/net/chelsio/sge.c (in both cases, the arrays contain 3 > elements): [snip] This is a bug. The array should contain 2 elements. Here is the fix. Signed-off-by: Scott Bardone Signed-off-by: Jeff Garzik --- drivers/net/chelsio/sge.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 2c5b849b7ba..30ff8ea1a40 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1021,7 +1021,7 @@ static void restart_tx_queues(struct sge *sge) if (test_and_clear_bit(nd->if_port, &sge->stopped_tx_queues) && netif_running(nd)) { - sge->stats.cmdQ_restarted[3]++; + sge->stats.cmdQ_restarted[2]++; netif_wake_queue(nd); } } @@ -1350,7 +1350,7 @@ static int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter, if (unlikely(credits < count)) { netif_stop_queue(dev); set_bit(dev->if_port, &sge->stopped_tx_queues); - sge->stats.cmdQ_full[3]++; + sge->stats.cmdQ_full[2]++; spin_unlock(&q->lock); if (!netif_queue_stopped(dev)) CH_ERR("%s: Tx ring full while queue awake!\n", @@ -1358,7 +1358,7 @@ static int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter, return NETDEV_TX_BUSY; } if (unlikely(credits - count < q->stop_thres)) { - sge->stats.cmdQ_full[3]++; + sge->stats.cmdQ_full[2]++; netif_stop_queue(dev); set_bit(dev->if_port, &sge->stopped_tx_queues); } -- cgit v1.2.3 From 9b15879aefe6a4c2236297df68c46498af26143d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 15 Mar 2006 11:30:44 +0100 Subject: [PATCH] spidernet: select FW_LOADER The spidernet drivers uses request_firmware() and thus needs to select FW_LOADER. Signed-off-by: Christoph Hellwig Signed-off-by: Paul Mackerras --- drivers/net/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index aa633fa95e6..8c1ad0fac7b 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2176,6 +2176,7 @@ config BNX2 config SPIDER_NET tristate "Spider Gigabit Ethernet driver" depends on PCI && PPC_CELL + select FW_LOADER help This driver supports the Gigabit Ethernet chips present on the Cell Processor-Based Blades from IBM. -- cgit v1.2.3 From 1867b117d944ce333e79b9a61c9a048656bee14b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Tue, 28 Feb 2006 09:48:28 -0600 Subject: [PATCH] Remove duplicated code from ipw2200.c As stated in a comment, the ipw2200 driver uses several routines that were borrowed from ieee80211_geo.c. As ipw2200 requires ieee80211, these routines are duplicated. The attached patch, which is sent as an attachment to preserve whitespace, converts ipw2200.c to use the ieee80211 versions, thereby reducing bloat in both the source and binary. Signed-Off-By: Larry Finger Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 128 ++++++----------------------------------- 1 file changed, 16 insertions(+), 112 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index ed37141319e..77932cf8500 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -153,12 +153,6 @@ static int init_supported_rates(struct ipw_priv *priv, static void ipw_set_hwcrypto_keys(struct ipw_priv *); static void ipw_send_wep_keys(struct ipw_priv *, int); -static int ipw_is_valid_channel(struct ieee80211_device *, u8); -static int ipw_channel_to_index(struct ieee80211_device *, u8); -static u8 ipw_freq_to_channel(struct ieee80211_device *, u32); -static int ipw_set_geo(struct ieee80211_device *, const struct ieee80211_geo *); -static const struct ieee80211_geo *ipw_get_geo(struct ieee80211_device *); - static int snprint_line(char *buf, size_t count, const u8 * data, u32 len, u32 ofs) { @@ -1654,7 +1648,7 @@ static ssize_t store_speed_scan(struct device *d, struct device_attribute *attr, break; } - if (ipw_is_valid_channel(priv->ieee, channel)) + if (ieee80211_is_valid_channel(priv->ieee, channel)) priv->speed_scan[pos++] = channel; else IPW_WARNING("Skipping invalid channel request: %d\n", @@ -2222,7 +2216,7 @@ static int ipw_send_tx_power(struct ipw_priv *priv, struct ipw_tx_power *power) static int ipw_set_tx_power(struct ipw_priv *priv) { - const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee); + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); struct ipw_tx_power tx_power; s8 max_power; int i; @@ -5562,7 +5556,7 @@ static int ipw_best_network(struct ipw_priv *priv, } /* Filter out invalid channel in current GEO */ - if (!ipw_is_valid_channel(priv->ieee, network->channel)) { + if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " "because of invalid channel in current GEO\n", escape_essid(network->ssid, network->ssid_len), @@ -5607,7 +5601,7 @@ static int ipw_best_network(struct ipw_priv *priv, static void ipw_adhoc_create(struct ipw_priv *priv, struct ieee80211_network *network) { - const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee); + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); int i; /* @@ -5622,10 +5616,10 @@ static void ipw_adhoc_create(struct ipw_priv *priv, * FW fatal error. * */ - switch (ipw_is_valid_channel(priv->ieee, priv->channel)) { + switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { case IEEE80211_52GHZ_BAND: network->mode = IEEE_A; - i = ipw_channel_to_index(priv->ieee, priv->channel); + i = ieee80211_channel_to_index(priv->ieee, priv->channel); if (i == -1) BUG(); if (geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY) { @@ -5639,7 +5633,7 @@ static void ipw_adhoc_create(struct ipw_priv *priv, network->mode = IEEE_G; else network->mode = IEEE_B; - i = ipw_channel_to_index(priv->ieee, priv->channel); + i = ieee80211_channel_to_index(priv->ieee, priv->channel); if (i == -1) BUG(); if (geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY) { @@ -5963,7 +5957,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, const struct ieee80211_geo *geo; int i; - geo = ipw_get_geo(priv->ieee); + geo = ieee80211_get_geo(priv->ieee); if (priv->ieee->freq_band & IEEE80211_52GHZ_BAND) { int start = channel_index; @@ -6023,7 +6017,7 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, channel_index++; scan->channels_list[channel_index] = channel; index = - ipw_channel_to_index(priv->ieee, channel); + ieee80211_channel_to_index(priv->ieee, channel); ipw_set_scan_type(scan, channel_index, geo->bg[index]. flags & @@ -6105,7 +6099,7 @@ static int ipw_request_scan(struct ipw_priv *priv) u8 channel; u8 band = 0; - switch (ipw_is_valid_channel(priv->ieee, priv->channel)) { + switch (ieee80211_is_valid_channel(priv->ieee, priv->channel)) { case IEEE80211_52GHZ_BAND: band = (u8) (IPW_A_MODE << 6) | 1; channel = priv->channel; @@ -8200,7 +8194,7 @@ static int ipw_wx_set_freq(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee); + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); struct iw_freq *fwrq = &wrqu->freq; int ret = 0, i; u8 channel, flags; @@ -8215,17 +8209,17 @@ static int ipw_wx_set_freq(struct net_device *dev, } /* if setting by freq convert to channel */ if (fwrq->e == 1) { - channel = ipw_freq_to_channel(priv->ieee, fwrq->m); + channel = ieee80211_freq_to_channel(priv->ieee, fwrq->m); if (channel == 0) return -EINVAL; } else channel = fwrq->m; - if (!(band = ipw_is_valid_channel(priv->ieee, channel))) + if (!(band = ieee80211_is_valid_channel(priv->ieee, channel))) return -EINVAL; if (priv->ieee->iw_mode == IW_MODE_ADHOC) { - i = ipw_channel_to_index(priv->ieee, channel); + i = ieee80211_channel_to_index(priv->ieee, channel); if (i == -1) return -EINVAL; @@ -8353,7 +8347,7 @@ static int ipw_wx_get_range(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); struct iw_range *range = (struct iw_range *)extra; - const struct ieee80211_geo *geo = ipw_get_geo(priv->ieee); + const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); int i = 0, j; wrqu->data.length = sizeof(*range); @@ -10617,96 +10611,6 @@ static const struct ieee80211_geo ipw_geos[] = { } }; -/* GEO code borrowed from ieee80211_geo.c */ -static int ipw_is_valid_channel(struct ieee80211_device *ieee, u8 channel) -{ - int i; - - /* Driver needs to initialize the geography map before using - * these helper functions */ - BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); - - if (ieee->freq_band & IEEE80211_24GHZ_BAND) - for (i = 0; i < ieee->geo.bg_channels; i++) - /* NOTE: If G mode is currently supported but - * this is a B only channel, we don't see it - * as valid. */ - if ((ieee->geo.bg[i].channel == channel) && - (!(ieee->mode & IEEE_G) || - !(ieee->geo.bg[i].flags & IEEE80211_CH_B_ONLY))) - return IEEE80211_24GHZ_BAND; - - if (ieee->freq_band & IEEE80211_52GHZ_BAND) - for (i = 0; i < ieee->geo.a_channels; i++) - if (ieee->geo.a[i].channel == channel) - return IEEE80211_52GHZ_BAND; - - return 0; -} - -static int ipw_channel_to_index(struct ieee80211_device *ieee, u8 channel) -{ - int i; - - /* Driver needs to initialize the geography map before using - * these helper functions */ - BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); - - if (ieee->freq_band & IEEE80211_24GHZ_BAND) - for (i = 0; i < ieee->geo.bg_channels; i++) - if (ieee->geo.bg[i].channel == channel) - return i; - - if (ieee->freq_band & IEEE80211_52GHZ_BAND) - for (i = 0; i < ieee->geo.a_channels; i++) - if (ieee->geo.a[i].channel == channel) - return i; - - return -1; -} - -static u8 ipw_freq_to_channel(struct ieee80211_device *ieee, u32 freq) -{ - int i; - - /* Driver needs to initialize the geography map before using - * these helper functions */ - BUG_ON(ieee->geo.bg_channels == 0 && ieee->geo.a_channels == 0); - - freq /= 100000; - - if (ieee->freq_band & IEEE80211_24GHZ_BAND) - for (i = 0; i < ieee->geo.bg_channels; i++) - if (ieee->geo.bg[i].freq == freq) - return ieee->geo.bg[i].channel; - - if (ieee->freq_band & IEEE80211_52GHZ_BAND) - for (i = 0; i < ieee->geo.a_channels; i++) - if (ieee->geo.a[i].freq == freq) - return ieee->geo.a[i].channel; - - return 0; -} - -static int ipw_set_geo(struct ieee80211_device *ieee, - const struct ieee80211_geo *geo) -{ - memcpy(ieee->geo.name, geo->name, 3); - ieee->geo.name[3] = '\0'; - ieee->geo.bg_channels = geo->bg_channels; - ieee->geo.a_channels = geo->a_channels; - memcpy(ieee->geo.bg, geo->bg, geo->bg_channels * - sizeof(struct ieee80211_channel)); - memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels * - sizeof(struct ieee80211_channel)); - return 0; -} - -static const struct ieee80211_geo *ipw_get_geo(struct ieee80211_device *ieee) -{ - return &ieee->geo; -} - #define MAX_HW_RESTARTS 5 static int ipw_up(struct ipw_priv *priv) { @@ -10753,7 +10657,7 @@ static int ipw_up(struct ipw_priv *priv) priv->eeprom[EEPROM_COUNTRY_CODE + 2]); j = 0; } - if (ipw_set_geo(priv->ieee, &ipw_geos[j])) { + if (ieee80211_set_geo(priv->ieee, &ipw_geos[j])) { IPW_WARNING("Could not set geography."); return 0; } -- cgit v1.2.3 From 53d0bcf82a5f59c96f1ffb202c02d2541200bf58 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 4 Mar 2006 13:14:31 +0100 Subject: [PATCH] drivers/net/wireless/ipw2200.c: make ipw_qos_current_mode() static This patch makes the needlessly global function ipw_qos_current_mode() static. Signed-off-by: Adrian Bunk Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 77932cf8500..d8a2a6fa72e 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -6562,7 +6562,7 @@ static int ipw_wx_set_mlme(struct net_device *dev, * get the modulation type of the current network or * the card current mode */ -u8 ipw_qos_current_mode(struct ipw_priv * priv) +static u8 ipw_qos_current_mode(struct ipw_priv * priv) { u8 mode = 0; -- cgit v1.2.3 From 48a847709f821b5eecd45ae7660add1869f9cd37 Mon Sep 17 00:00:00 2001 From: Henrik Brix Andersen Date: Tue, 14 Feb 2006 09:09:52 +0800 Subject: [PATCH] ipw2200: print geography code upon module load Given the amount of support requests for the meaning of the geography code I've written a patch for printing this information on module load no matter the debug level. I've also added a section to the README.ipw2200 file listing the geography codes and their meaning. Signed-off-by: Henrik Brix Andersen Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index d8a2a6fa72e..a7483809d87 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -10364,6 +10364,9 @@ static int ipw_config(struct ipw_priv *priv) * not intended for resale of the above mentioned Intel adapters has * not been tested. * + * Remember to update the table in README.ipw2200 when changing this + * table. + * */ static const struct ieee80211_geo ipw_geos[] = { { /* Restricted */ @@ -10662,9 +10665,6 @@ static int ipw_up(struct ipw_priv *priv) return 0; } - IPW_DEBUG_INFO("Geography %03d [%s] detected.\n", - j, priv->ieee->geo.name); - if (priv->status & STATUS_RF_KILL_SW) { IPW_WARNING("Radio disabled by module parameter.\n"); return 0; @@ -10985,6 +10985,12 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) IPW_ERROR("failed to register network device\n"); goto out_remove_sysfs; } + + printk(KERN_INFO DRV_NAME ": Detected geography %s (%d 802.11bg " + "channels, %d 802.11a channels)\n", + priv->ieee->geo.name, priv->ieee->geo.bg_channels, + priv->ieee->geo.a_channels); + return 0; out_remove_sysfs: -- cgit v1.2.3 From f697014af90c1db3c7b299327bf5a9548945b8bf Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Tue, 14 Feb 2006 09:10:51 +0800 Subject: [PATCH] ipw2200: stop netdev queue if h/w doesn't have space for new packets The patch roll back the change we made to support for the ability to start/stop independent Tx queues within a single net device in order to support 802.11e QoS. We need to be able to indicate to the upper layers that packets of a given priority can not be sent any more without halting transmission of all packets, and without rescheduling high priority packets down to the next priority level. So we return NETDEV_TX_BUSY in this case and rely on the stack would take care of rescheduling... which it apparently does immediately and consumes the CPU. This caused the ksoftirqd kernel thread consuming almost all the CPU... To put the code back to the way it was before we made these changes we put the call netif_queue_stop back in ipw_tx_skb. This effectively disables multiple priority based transmit queues for 802.11e, but given that its broken anyway... Signed-off-by: James Ketrenos Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index a7483809d87..4722de13f1d 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -9648,11 +9648,6 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, u16 remaining_bytes; int fc; - /* If there isn't room in the queue, we return busy and let the - * network stack requeue the packet for us */ - if (ipw_queue_space(q) < q->high_mark) - return NETDEV_TX_BUSY; - switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: hdr_len = IEEE80211_3ADDR_LEN; @@ -9818,6 +9813,9 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, q->first_empty = ipw_queue_inc_wrap(q->first_empty, q->n_bd); ipw_write32(priv, q->reg_w, q->first_empty); + if (ipw_queue_space(q) < q->high_mark) + netif_stop_queue(priv->net_dev); + return NETDEV_TX_OK; drop: -- cgit v1.2.3 From 85149bace30eae1dc1f86d2c327329673123dd22 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 14 Feb 2006 16:02:22 +0800 Subject: [PATCH] ipw2200: fix a potential NULL pointer dereference Only on CONFIG_IPW2200_DEBUG is not defined Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 4722de13f1d..129891feb43 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7809,12 +7809,10 @@ static void ipw_rx(struct ipw_priv *priv) while (i != r) { rxb = priv->rxq->queue[i]; -#ifdef CONFIG_IPW2200_DEBUG if (unlikely(rxb == NULL)) { printk(KERN_CRIT "Queue not allocated!\n"); break; } -#endif priv->rxq->queue[i] = NULL; pci_dma_sync_single_for_cpu(priv->pci_dev, rxb->dma_addr, -- cgit v1.2.3 From 9d0be03aeeadcd59bd8f57219817e876a5e88e88 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Wed, 15 Feb 2006 06:18:19 +0800 Subject: [PATCH] ipw2200: use generic ieee80211_get_hdrlen() to get packet length replace ipw2200 specific frame_hdr_len() with generic ieee80211 routine ieee80211_get_hdrlen() Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 3 ++- drivers/net/wireless/ipw2200.h | 23 ----------------------- 2 files changed, 2 insertions(+), 24 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 129891feb43..b2bbdf982b0 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7895,7 +7895,8 @@ static void ipw_rx(struct ipw_priv *priv) le16_to_cpu(pkt->u.frame.length)); if (le16_to_cpu(pkt->u.frame.length) < - frame_hdr_len(header)) { + ieee80211_get_hdrlen(le16_to_cpu( + header->frame_ctl))) { IPW_DEBUG_DROP ("Received packet is too small. " "Dropping.\n"); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 5405ba105ab..c2a7aa32f72 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1907,27 +1907,4 @@ struct ipw_cmd_log { #define IPW_MAX_CONFIG_RETRIES 10 -static inline u32 frame_hdr_len(struct ieee80211_hdr_4addr *hdr) -{ - u32 retval; - u16 fc; - - retval = sizeof(struct ieee80211_hdr_3addr); - fc = le16_to_cpu(hdr->frame_ctl); - - /* - * Function ToDS FromDS - * IBSS 0 0 - * To AP 1 0 - * From AP 0 1 - * WDS (bridge) 1 1 - * - * Only WDS frames use Address4 among them. --YZ - */ - if (!(fc & IEEE80211_FCTL_TODS) || !(fc & IEEE80211_FCTL_FROMDS)) - retval -= ETH_ALEN; - - return retval; -} - #endif /* __ipw2200_h__ */ -- cgit v1.2.3 From b191608a451e75ed7f979cac268f5f423176feb3 Mon Sep 17 00:00:00 2001 From: Bill Moss Date: Wed, 15 Feb 2006 08:50:18 +0800 Subject: [PATCH] ipw2200: Add signal level to iwlist scan output This patch does two things. It uses the parameter IW_QUAL_DBM which is new in WE-19 to cause signal level and noise to be reported in dBm by the wireless tools. It also defines the signal level as an unsigned integer so that the signal level will be reported by iwlist iface scan. Signed-off-by: Bill Moss Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index b2bbdf982b0..c38d6a5fe9a 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7831,7 +7831,8 @@ static void ipw_rx(struct ipw_priv *priv) le16_to_cpu(pkt->u.frame.rssi_dbm) - IPW_RSSI_TO_DBM, .signal = - le16_to_cpu(pkt->u.frame.signal), + le16_to_cpu(pkt->u.frame.rssi_dbm) - + IPW_RSSI_TO_DBM + 0x100, .noise = le16_to_cpu(pkt->u.frame.noise), .rate = pkt->u.frame.rate, @@ -8358,7 +8359,7 @@ static int ipw_wx_get_range(struct net_device *dev, range->max_qual.qual = 100; /* TODO: Find real max RSSI and stick here */ range->max_qual.level = 0; - range->max_qual.noise = priv->ieee->worst_rssi + 0x100; + range->max_qual.noise = 0; range->max_qual.updated = 7; /* Updated all three */ range->avg_qual.qual = 70; @@ -9568,7 +9569,7 @@ static struct iw_statistics *ipw_get_wireless_stats(struct net_device *dev) wstats->qual.level = average_value(&priv->average_rssi); wstats->qual.noise = average_value(&priv->average_noise); wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | - IW_QUAL_NOISE_UPDATED; + IW_QUAL_NOISE_UPDATED | IW_QUAL_DBM; wstats->miss.beacon = average_value(&priv->average_missed_beacons); wstats->discard.retries = priv->last_tx_failures; -- cgit v1.2.3 From 8da374fc44a5e0fb71a485497cae38eb562d078c Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 17 Feb 2006 07:46:16 +0800 Subject: [PATCH] ipw2200: remove the WPA card associates to non-WPA AP checking wpa_supplicant needs to set wpa_enabled unconditionally, with this check it hasn't been possible to connect to non-WPA networks using wpa_supplicant. So remove below check. if (priv->ieee->wpa_enabled && network->wpa_ie_len == 0 && network->rsn_ie_len == 0) Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index c38d6a5fe9a..dfa2efb3e21 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -5527,15 +5527,6 @@ static int ipw_best_network(struct ipw_priv *priv, return 0; } - if (priv->ieee->wpa_enabled && - network->wpa_ie_len == 0 && network->rsn_ie_len == 0) { - IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " - "because of WPA capability mismatch.\n", - escape_essid(network->ssid, network->ssid_len), - MAC_ARG(network->bssid)); - return 0; - } - if ((priv->config & CFG_STATIC_BSSID) && memcmp(network->bssid, priv->bssid, ETH_ALEN)) { IPW_DEBUG_ASSOC("Network '%s (" MAC_FMT ")' excluded " -- cgit v1.2.3 From d6d5b5c13e5003c9d33dcdcfdf1febc6efd7d319 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 16 Feb 2006 16:21:09 +0800 Subject: [PATCH] ipw2200: Fix rf_kill is activated after mode change with 'disable=1' When loading the ipw2200 module with disabled=1, rf_kill is activated after every mode change. This is caused by ipw_sw_reset() is called when a mode is changed. The patch fixed the problem by distinguishing the purposes with the 'option' paramenter. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index dfa2efb3e21..b80ebd37483 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -7978,7 +7978,14 @@ static void ipw_rx(struct ipw_priv *priv) #define DEFAULT_SHORT_RETRY_LIMIT 7U #define DEFAULT_LONG_RETRY_LIMIT 4U -static int ipw_sw_reset(struct ipw_priv *priv, int init) +/** + * ipw_sw_reset + * @option: options to control different reset behaviour + * 0 = reset everything except the 'disable' module_param + * 1 = reset everything and print out driver info (for probe only) + * 2 = reset everything + */ +static int ipw_sw_reset(struct ipw_priv *priv, int option) { int band, modulation; int old_mode = priv->ieee->iw_mode; @@ -8005,7 +8012,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init) priv->essid_len = 0; memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - if (disable) { + if (disable && option) { priv->status |= STATUS_RF_KILL_SW; IPW_DEBUG_INFO("Radio disabled.\n"); } @@ -8057,7 +8064,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init) if ((priv->pci_dev->device == 0x4223) || (priv->pci_dev->device == 0x4224)) { - if (init) + if (option == 2) printk(KERN_INFO DRV_NAME ": Detected Intel PRO/Wireless 2915ABG Network " "Connection\n"); @@ -8068,7 +8075,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int init) priv->adapter = IPW_2915ABG; priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; } else { - if (init) + if (option == 2) printk(KERN_INFO DRV_NAME ": Detected Intel PRO/Wireless 2200BG Network " "Connection\n"); @@ -9380,7 +9387,7 @@ static int ipw_wx_sw_reset(struct net_device *dev, mutex_lock(&priv->mutex); - ret = ipw_sw_reset(priv, 0); + ret = ipw_sw_reset(priv, 2); if (!ret) { free_firmware(); ipw_adapter_restart(priv); -- cgit v1.2.3 From e8c69e27d14a5fb15df9967f8c8ec5978af33ba8 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 17 Feb 2006 08:25:12 +0800 Subject: [PATCH] ipw2200: Fix ipw_sw_reset() implementation inconsistent with comment Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index b80ebd37483..e9804450ca6 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -8064,7 +8064,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) if ((priv->pci_dev->device == 0x4223) || (priv->pci_dev->device == 0x4224)) { - if (option == 2) + if (option == 1) printk(KERN_INFO DRV_NAME ": Detected Intel PRO/Wireless 2915ABG Network " "Connection\n"); @@ -8075,7 +8075,7 @@ static int ipw_sw_reset(struct ipw_priv *priv, int option) priv->adapter = IPW_2915ABG; priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; } else { - if (option == 2) + if (option == 1) printk(KERN_INFO DRV_NAME ": Detected Intel PRO/Wireless 2200BG Network " "Connection\n"); -- cgit v1.2.3 From e815de422c1dc2fe787c6f3edba81f3cf0176e32 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 2 Mar 2006 05:55:51 +0800 Subject: [PATCH] ipw2200: Filter unsupported channels out in ad-hoc mode Currently iwlist ethX freq[uency]/channel lists all the channels the card supported for the current region, which includes some channels can only be used in infrastructure mode. This patch filters these channels out if the card is currently in ad-hoc mode. Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index e9804450ca6..d2fc8400d3a 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -8387,20 +8387,28 @@ static int ipw_wx_get_range(struct net_device *dev, i = 0; if (priv->ieee->mode & (IEEE_B | IEEE_G)) { - for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES; - i++, j++) { + for (j = 0; j < geo->bg_channels && i < IW_MAX_FREQUENCIES; j++) { + if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && + (geo->bg[j].flags & IEEE80211_CH_PASSIVE_ONLY)) + continue; + range->freq[i].i = geo->bg[j].channel; range->freq[i].m = geo->bg[j].freq * 100000; range->freq[i].e = 1; + i++; } } if (priv->ieee->mode & IEEE_A) { - for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES; - i++, j++) { + for (j = 0; j < geo->a_channels && i < IW_MAX_FREQUENCIES; j++) { + if ((priv->ieee->iw_mode == IW_MODE_ADHOC) && + (geo->a[j].flags & IEEE80211_CH_PASSIVE_ONLY)) + continue; + range->freq[i].i = geo->a[j].channel; range->freq[i].m = geo->a[j].freq * 100000; range->freq[i].e = 1; + i++; } } -- cgit v1.2.3 From 1d1b09eb144e414ade1f44e21852fc60f2cf965b Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Thu, 2 Mar 2006 06:40:59 +0800 Subject: [PATCH] ipw2200: Change debug level for firmware error logging Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index d2fc8400d3a..d12ef04fb4b 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1796,9 +1796,9 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) } if (inta & IPW_INTA_BIT_FATAL_ERROR) { - IPW_ERROR("Firmware error detected. Restarting.\n"); + IPW_WARNING("Firmware error detected. Restarting.\n"); if (priv->error) { - IPW_ERROR("Sysfs 'error' log already exists.\n"); + IPW_DEBUG_FW("Sysfs 'error' log already exists.\n"); #ifdef CONFIG_IPW2200_DEBUG if (ipw_debug_level & IPW_DL_FW_ERRORS) { struct ipw_fw_error *error = @@ -1811,10 +1811,10 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) } else { priv->error = ipw_alloc_error_log(priv); if (priv->error) - IPW_ERROR("Sysfs 'error' log captured.\n"); + IPW_DEBUG_FW("Sysfs 'error' log captured.\n"); else - IPW_ERROR("Error allocating sysfs 'error' " - "log.\n"); + IPW_DEBUG_FW("Error allocating sysfs 'error' " + "log.\n"); #ifdef CONFIG_IPW2200_DEBUG if (ipw_debug_level & IPW_DL_FW_ERRORS) ipw_dump_error_log(priv, priv->error); -- cgit v1.2.3 From 3e1555bae145ab2d079a1823cbdd5c486503d147 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Mon, 6 Mar 2006 05:48:37 +0800 Subject: [PATCH] ipw2200: export `debug' module param only if CONFIG_IPW2200_DEBUG Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index d12ef04fb4b..a56a77e8f32 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -11185,8 +11185,10 @@ MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); module_param(led, int, 0444); MODULE_PARM_DESC(led, "enable led control on some systems (default 0 off)\n"); +#ifdef CONFIG_IPW2200_DEBUG module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); +#endif module_param(channel, int, 0444); MODULE_PARM_DESC(channel, "channel to limit associate to (default 0 [ANY])"); -- cgit v1.2.3 From 12977154e7cb4d72b1295f009a040c56a7e05d90 Mon Sep 17 00:00:00 2001 From: "Cahill, Ben M" Date: Wed, 8 Mar 2006 02:58:02 +0800 Subject: [PATCH] ipw2200: Set a meaningful silence threshold value Set a meaningful silence threshold value (replacing our previous "0" default), which gets rid of the gratuitous "Link deterioration" notifications that we've been receiving from firmware. This notification feature tells the driver information to help it determine when to pre-emptively restart the firmware/ucode in anticipation of firmware errors! But since setting this new threshold, I haven't seen any such notifications. At least it keeps the logs a little less busy. Signed-off-by: Cahill, Ben M Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 8 ++++---- drivers/net/wireless/ipw2200.h | 9 ++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index a56a77e8f32..06909cbc980 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -4541,10 +4541,9 @@ static void ipw_rx_notification(struct ipw_priv *priv, if (notif->size == sizeof(*x)) { IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, - "link deterioration: '%s' " MAC_FMT - " \n", escape_essid(priv->essid, - priv->essid_len), - MAC_ARG(priv->bssid)); + "link deterioration: type %d, cnt %d\n", + x->silence_notification_type, + x->silence_count); memcpy(&priv->last_link_deterioration, x, sizeof(*x)); } else { @@ -9607,6 +9606,7 @@ static void init_sys_config(struct ipw_sys_config *sys_config) sys_config->enable_cts_to_self = 0; sys_config->bt_coexist_collision_thr = 0; sys_config->pass_noise_stats_to_host = 1; //1 -- fix for 256 + sys_config->silence_threshold = 0x1e; } static int ipw_net_open(struct net_device *dev) diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index c2a7aa32f72..d9f57f456fb 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -618,13 +618,16 @@ struct notif_tgi_tx_key { u8 reserved; } __attribute__ ((packed)); +#define SILENCE_OVER_THRESH (1) +#define SILENCE_UNDER_THRESH (2) + struct notif_link_deterioration { struct ipw_cmd_stats stats; u8 rate; u8 modulation; struct rate_histogram histogram; - u8 reserved1; - u16 reserved2; + u8 silence_notification_type; /* SILENCE_OVER/UNDER_THRESH */ + u16 silence_count; } __attribute__ ((packed)); struct notif_association { @@ -782,7 +785,7 @@ struct ipw_sys_config { u8 enable_cts_to_self; u8 enable_multicast_filtering; u8 bt_coexist_collision_thr; - u8 reserved2; + u8 silence_threshold; u8 accept_all_mgmt_bcpr; u8 accept_all_mgtm_frames; u8 pass_noise_stats_to_host; -- cgit v1.2.3 From 71de1f3dd14e3e39cef929506a9526779f5a447d Mon Sep 17 00:00:00 2001 From: "Cahill, Ben M" Date: Wed, 8 Mar 2006 03:02:27 +0800 Subject: [PATCH] ipw2200: Enables the "slow diversity" algorithm This forces one antenna or the other, if the background noise is significantly quieter in one than the other. It favors the quieter antenna, and won't kick in unless the difference is significant. Signed-off-by: Cahill, Ben M Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 2 +- drivers/net/wireless/ipw2200.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 06909cbc980..954a095eeb5 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -9600,7 +9600,7 @@ static void init_sys_config(struct ipw_sys_config *sys_config) sys_config->disable_unicast_decryption = 1; sys_config->exclude_multicast_unencrypted = 0; sys_config->disable_multicast_decryption = 1; - sys_config->antenna_diversity = CFG_SYS_ANTENNA_BOTH; + sys_config->antenna_diversity = CFG_SYS_ANTENNA_SLOW_DIV; sys_config->pass_crc_to_host = 0; /* TODO: See if 1 gives us FCS */ sys_config->dot11g_auto_detection = 0; sys_config->enable_cts_to_self = 0; diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index d9f57f456fb..e8f133666c6 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1895,6 +1895,7 @@ struct ipw_cmd_log { #define CFG_SYS_ANTENNA_BOTH 0x00 /* NIC selects best antenna */ #define CFG_SYS_ANTENNA_A 0x01 /* force antenna A */ #define CFG_SYS_ANTENNA_B 0x03 /* force antenna B */ +#define CFG_SYS_ANTENNA_SLOW_DIV 0x02 /* consider background noise */ /* * The definitions below were lifted off the ipw2100 driver, which only -- cgit v1.2.3 From 651be26f2daf31e61faf4b55ada709cf39ec76a2 Mon Sep 17 00:00:00 2001 From: Olivier Hochreutiner Date: Wed, 8 Mar 2006 03:13:55 +0800 Subject: [PATCH] ipw2200: wireless extension sensitivity threshold support The patch allows the user to set the handover threshold, i.e. the number of consecutively missed beacons that will trigger a roaming attempt. The disassociation threshold is set to 3 times the handover threshold. Signed-off-by: Olivier Hochreutiner Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 48 ++++++++++++++++++++++++++++++++++++++++++ drivers/net/wireless/ipw2200.h | 4 +++- 2 files changed, 51 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 954a095eeb5..078f33b01c2 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -8608,6 +8608,52 @@ static int ipw_wx_get_nick(struct net_device *dev, return 0; } +static int ipw_wx_set_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + int err = 0; + + IPW_DEBUG_WX("Setting roaming threshold to %d\n", wrqu->sens.value); + IPW_DEBUG_WX("Setting disassociate threshold to %d\n", 3*wrqu->sens.value); + mutex_lock(&priv->mutex); + + if (wrqu->sens.fixed == 0) + { + priv->roaming_threshold = IPW_MB_ROAMING_THRESHOLD_DEFAULT; + priv->disassociate_threshold = IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT; + goto out; + } + if ((wrqu->sens.value > IPW_MB_ROAMING_THRESHOLD_MAX) || + (wrqu->sens.value < IPW_MB_ROAMING_THRESHOLD_MIN)) { + err = -EINVAL; + goto out; + } + + priv->roaming_threshold = wrqu->sens.value; + priv->disassociate_threshold = 3*wrqu->sens.value; + out: + mutex_unlock(&priv->mutex); + return err; +} + +static int ipw_wx_get_sens(struct net_device *dev, + struct iw_request_info *info, + union iwreq_data *wrqu, char *extra) +{ + struct ipw_priv *priv = ieee80211_priv(dev); + mutex_lock(&priv->mutex); + wrqu->sens.fixed = 1; + wrqu->sens.value = priv->roaming_threshold; + mutex_unlock(&priv->mutex); + + IPW_DEBUG_WX("GET roaming threshold -> %s %d \n", + wrqu->power.disabled ? "OFF" : "ON", wrqu->power.value); + + return 0; +} + static int ipw_wx_set_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) @@ -9429,6 +9475,8 @@ static iw_handler ipw_wx_handlers[] = { IW_IOCTL(SIOCGIWFREQ) = ipw_wx_get_freq, IW_IOCTL(SIOCSIWMODE) = ipw_wx_set_mode, IW_IOCTL(SIOCGIWMODE) = ipw_wx_get_mode, + IW_IOCTL(SIOCSIWSENS) = ipw_wx_set_sens, + IW_IOCTL(SIOCGIWSENS) = ipw_wx_get_sens, IW_IOCTL(SIOCGIWRANGE) = ipw_wx_get_range, IW_IOCTL(SIOCSIWAP) = ipw_wx_set_wap, IW_IOCTL(SIOCGIWAP) = ipw_wx_get_wap, diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index e8f133666c6..2033fc6f189 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -246,8 +246,10 @@ enum connection_manager_assoc_states { #define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31 #define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1 -#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT 24 +#define IPW_MB_ROAMING_THRESHOLD_MIN 1 #define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8 +#define IPW_MB_ROAMING_THRESHOLD_MAX 30 +#define IPW_MB_DISASSOCIATE_THRESHOLD_DEFAULT 3*IPW_MB_ROAMING_THRESHOLD_DEFAULT #define IPW_REAL_RATE_RX_PACKET_THRESHOLD 300 #define MACADRR_BYTE_LEN 6 -- cgit v1.2.3 From 9006ea75cfaded82acbc34d03e9d4e86447f40a9 Mon Sep 17 00:00:00 2001 From: James Ketrenos Date: Wed, 8 Mar 2006 03:22:28 +0800 Subject: [PATCH] ipw2200: switch to the new ipw2200-fw-3.0 image format This patch modifies the driver to support the ipw2200-fw-3.0 image format. The 3.0 fw image does not add any new capabilities, but as a result of image format changes, it should fix two problems experienced by users: 1) Race conditions with the request_firmware interface and udev/hotplug are improved as only a single request_firmware call is now required to load the firmware and microcode (vs. 3 separate calls previously) 2) The monitor mode firmware (sniffer) is now packaged with the correct boot image so it can now function without frequent restarts. Note: Once you apply this patch, you will also need to upgrade your firmware image to the 3.0 version available from: http://ipw2200.sf.net/firmware.php Signed-off-by: James Ketrenos Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 165 ++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 101 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 078f33b01c2..0b74b5a1664 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -2829,33 +2829,11 @@ static void ipw_arc_release(struct ipw_priv *priv) mdelay(5); } -struct fw_header { - u32 version; - u32 mode; -}; - struct fw_chunk { u32 address; u32 length; }; -#define IPW_FW_MAJOR_VERSION 2 -#define IPW_FW_MINOR_VERSION 4 - -#define IPW_FW_MINOR(x) ((x & 0xff) >> 8) -#define IPW_FW_MAJOR(x) (x & 0xff) - -#define IPW_FW_VERSION ((IPW_FW_MINOR_VERSION << 8) | IPW_FW_MAJOR_VERSION) - -#define IPW_FW_PREFIX "ipw-" __stringify(IPW_FW_MAJOR_VERSION) \ -"." __stringify(IPW_FW_MINOR_VERSION) "-" - -#if IPW_FW_MAJOR_VERSION >= 2 && IPW_FW_MINOR_VERSION > 0 -#define IPW_FW_NAME(x) IPW_FW_PREFIX "" x ".fw" -#else -#define IPW_FW_NAME(x) "ipw2200_" x ".fw" -#endif - static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) { int rc = 0, i, addr; @@ -3124,33 +3102,47 @@ static int ipw_reset_nic(struct ipw_priv *priv) return rc; } + +struct ipw_fw { + u32 ver; + u32 boot_size; + u32 ucode_size; + u32 fw_size; + u8 data[0]; +}; + static int ipw_get_fw(struct ipw_priv *priv, - const struct firmware **fw, const char *name) + const struct firmware **raw, const char *name) { - struct fw_header *header; + struct ipw_fw *fw; int rc; /* ask firmware_class module to get the boot firmware off disk */ - rc = request_firmware(fw, name, &priv->pci_dev->dev); + rc = request_firmware(raw, name, &priv->pci_dev->dev); if (rc < 0) { - IPW_ERROR("%s load failed: Reason %d\n", name, rc); + IPW_ERROR("%s request_firmware failed: Reason %d\n", name, rc); return rc; } - header = (struct fw_header *)(*fw)->data; - if (IPW_FW_MAJOR(le32_to_cpu(header->version)) != IPW_FW_MAJOR_VERSION) { - IPW_ERROR("'%s' firmware version not compatible (%d != %d)\n", - name, - IPW_FW_MAJOR(le32_to_cpu(header->version)), - IPW_FW_MAJOR_VERSION); + if ((*raw)->size < sizeof(*fw)) { + IPW_ERROR("%s is too small (%zd)\n", name, (*raw)->size); + return -EINVAL; + } + + fw = (void *)(*raw)->data; + + if ((*raw)->size < sizeof(*fw) + + fw->boot_size + fw->ucode_size + fw->fw_size) { + IPW_ERROR("%s is too small or corrupt (%zd)\n", + name, (*raw)->size); return -EINVAL; } - IPW_DEBUG_INFO("Loading firmware '%s' file v%d.%d (%zd bytes)\n", + IPW_DEBUG_INFO("Read firmware '%s' image v%d.%d (%zd bytes)\n", name, - IPW_FW_MAJOR(le32_to_cpu(header->version)), - IPW_FW_MINOR(le32_to_cpu(header->version)), - (*fw)->size - sizeof(struct fw_header)); + le32_to_cpu(fw->ver) >> 16, + le32_to_cpu(fw->ver) & 0xff, + (*raw)->size - sizeof(*fw)); return 0; } @@ -3190,17 +3182,13 @@ static void ipw_rx_queue_reset(struct ipw_priv *priv, #ifdef CONFIG_PM static int fw_loaded = 0; -static const struct firmware *bootfw = NULL; -static const struct firmware *firmware = NULL; -static const struct firmware *ucode = NULL; +static const struct firmware *raw = NULL; static void free_firmware(void) { if (fw_loaded) { - release_firmware(bootfw); - release_firmware(ucode); - release_firmware(firmware); - bootfw = ucode = firmware = NULL; + release_firmware(raw); + raw = NULL; fw_loaded = 0; } } @@ -3211,32 +3199,46 @@ static void free_firmware(void) static int ipw_load(struct ipw_priv *priv) { #ifndef CONFIG_PM - const struct firmware *bootfw = NULL; - const struct firmware *firmware = NULL; - const struct firmware *ucode = NULL; + const struct firmware *raw = NULL; #endif - char *ucode_name; - char *fw_name; + struct ipw_fw *fw; + u8 *boot_img, *ucode_img, *fw_img; + u8 *name = NULL; int rc = 0, retries = 3; switch (priv->ieee->iw_mode) { case IW_MODE_ADHOC: - ucode_name = IPW_FW_NAME("ibss_ucode"); - fw_name = IPW_FW_NAME("ibss"); + name = "ipw2200-ibss.fw"; break; #ifdef CONFIG_IPW2200_MONITOR case IW_MODE_MONITOR: - ucode_name = IPW_FW_NAME("sniffer_ucode"); - fw_name = IPW_FW_NAME("sniffer"); + name = "ipw2200-sniffer.fw"; break; #endif case IW_MODE_INFRA: - ucode_name = IPW_FW_NAME("bss_ucode"); - fw_name = IPW_FW_NAME("bss"); + name = "ipw2200-bss.fw"; break; - default: + } + + if (!name) { rc = -EINVAL; + goto error; + } + +#ifdef CONFIG_PM + if (!fw_loaded) { +#endif + rc = ipw_get_fw(priv, &raw, name); + if (rc < 0) + goto error; +#ifdef CONFIG_PM } +#endif + + fw = (void *)raw->data; + boot_img = &fw->data[0]; + ucode_img = &fw->data[fw->boot_size]; + fw_img = &fw->data[fw->boot_size + fw->ucode_size]; if (rc < 0) goto error; @@ -3269,18 +3271,8 @@ static int ipw_load(struct ipw_priv *priv) ipw_zero_memory(priv, IPW_NIC_SRAM_LOWER_BOUND, IPW_NIC_SRAM_UPPER_BOUND - IPW_NIC_SRAM_LOWER_BOUND); -#ifdef CONFIG_PM - if (!fw_loaded) { -#endif - rc = ipw_get_fw(priv, &bootfw, IPW_FW_NAME("boot")); - if (rc < 0) - goto error; -#ifdef CONFIG_PM - } -#endif /* DMA the initial boot firmware into the device */ - rc = ipw_load_firmware(priv, bootfw->data + sizeof(struct fw_header), - bootfw->size - sizeof(struct fw_header)); + rc = ipw_load_firmware(priv, boot_img, fw->boot_size); if (rc < 0) { IPW_ERROR("Unable to load boot firmware: %d\n", rc); goto error; @@ -3301,19 +3293,8 @@ static int ipw_load(struct ipw_priv *priv) /* ack fw init done interrupt */ ipw_write32(priv, IPW_INTA_RW, IPW_INTA_BIT_FW_INITIALIZATION_DONE); -#ifdef CONFIG_PM - if (!fw_loaded) { -#endif - rc = ipw_get_fw(priv, &ucode, ucode_name); - if (rc < 0) - goto error; -#ifdef CONFIG_PM - } -#endif - /* DMA the ucode into the device */ - rc = ipw_load_ucode(priv, ucode->data + sizeof(struct fw_header), - ucode->size - sizeof(struct fw_header)); + rc = ipw_load_ucode(priv, ucode_img, fw->ucode_size); if (rc < 0) { IPW_ERROR("Unable to load ucode: %d\n", rc); goto error; @@ -3322,20 +3303,8 @@ static int ipw_load(struct ipw_priv *priv) /* stop nic */ ipw_stop_nic(priv); -#ifdef CONFIG_PM - if (!fw_loaded) { -#endif - rc = ipw_get_fw(priv, &firmware, fw_name); - if (rc < 0) - goto error; -#ifdef CONFIG_PM - } -#endif - /* DMA bss firmware into the device */ - rc = ipw_load_firmware(priv, firmware->data + - sizeof(struct fw_header), - firmware->size - sizeof(struct fw_header)); + rc = ipw_load_firmware(priv, fw_img, fw->fw_size); if (rc < 0) { IPW_ERROR("Unable to load firmware: %d\n", rc); goto error; @@ -3400,9 +3369,7 @@ static int ipw_load(struct ipw_priv *priv) ipw_write32(priv, IPW_INTA_RW, IPW_INTA_MASK_ALL); #ifndef CONFIG_PM - release_firmware(bootfw); - release_firmware(ucode); - release_firmware(firmware); + release_firmware(raw); #endif return 0; @@ -3412,15 +3379,11 @@ static int ipw_load(struct ipw_priv *priv) priv->rxq = NULL; } ipw_tx_queue_free(priv); - if (bootfw) - release_firmware(bootfw); - if (ucode) - release_firmware(ucode); - if (firmware) - release_firmware(firmware); + if (raw) + release_firmware(raw); #ifdef CONFIG_PM fw_loaded = 0; - bootfw = ucode = firmware = NULL; + raw = NULL; #endif return rc; -- cgit v1.2.3 From 7c567894480daef05bc13abdc4b9414541e245cb Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Fri, 24 Feb 2006 04:20:48 +0800 Subject: [PATCH] ipw2200: Update ipw2200 version stamp to 1.1.1 Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 0b74b5a1664..65c5b1422ec 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -33,7 +33,7 @@ #include "ipw2200.h" #include -#define IPW2200_VERSION "git-1.0.10" +#define IPW2200_VERSION "git-1.1.1" #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" #define DRV_COPYRIGHT "Copyright(c) 2003-2005 Intel Corporation" #define DRV_VERSION IPW2200_VERSION -- cgit v1.2.3 From 71e585fca25c9ccde82196fd1aef78e34312e899 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 11 Mar 2006 04:42:58 +0100 Subject: [PATCH] drivers/net/wireless/ipw2200.c: fix an array overun This patch fixes a big array overun found by the Coverity checker. Signed-off-by: Adrian Bunk Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2200.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 65c5b1422ec..93d53f9dab0 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -9972,9 +9972,8 @@ static int ipw_ethtool_set_eeprom(struct net_device *dev, return -EINVAL; mutex_lock(&p->mutex); memcpy(&p->eeprom[eeprom->offset], bytes, eeprom->len); - for (i = IPW_EEPROM_DATA; - i < IPW_EEPROM_DATA + IPW_EEPROM_IMAGE_SIZE; i++) - ipw_write8(p, i, p->eeprom[i]); + for (i = 0; i < IPW_EEPROM_IMAGE_SIZE; i++) + ipw_write8(p, i + IPW_EEPROM_DATA, p->eeprom[i]); mutex_unlock(&p->mutex); return 0; } -- cgit v1.2.3 From 171e7b2f1f50f112d3ce8a829a3e79c5739b3132 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Wed, 15 Feb 2006 07:17:56 +0800 Subject: [PATCH] ipw2x00: expend Copyright to 2006 Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 4 ++-- drivers/net/wireless/ipw2100.h | 2 +- drivers/net/wireless/ipw2200.c | 4 ++-- drivers/net/wireless/ipw2200.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index eb79198ac45..84f63876bf7 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. + Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as @@ -172,7 +172,7 @@ that only one external action is invoked at a time. #define DRV_NAME "ipw2100" #define DRV_VERSION IPW2100_VERSION #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2100 Network Driver" -#define DRV_COPYRIGHT "Copyright(c) 2003-2005 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation" /* Debugging stuff */ #ifdef CONFIG_IPW2100_DEBUG diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index 51360910d22..948d426fcf9 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright(c) 2003 - 2004 Intel Corporation. All rights reserved. + Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 93d53f9dab0..9dce522526c 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. + Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. 802.11 status code portion of this file from ethereal-0.10.6: Copyright 2000, Axis Communications AB @@ -35,7 +35,7 @@ #define IPW2200_VERSION "git-1.1.1" #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" -#define DRV_COPYRIGHT "Copyright(c) 2003-2005 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003-2006 Intel Corporation" #define DRV_VERSION IPW2200_VERSION #define ETH_P_80211_STATS (ETH_P_80211_RAW + 1) diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 2033fc6f189..4b980490070 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -1,6 +1,6 @@ /****************************************************************************** - Copyright(c) 2003 - 2005 Intel Corporation. All rights reserved. + Copyright(c) 2003 - 2006 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as -- cgit v1.2.3 From 15745a7dd1ac6bf1ef7959040f864c78a95aa35b Mon Sep 17 00:00:00 2001 From: Stefan Rompf Date: Tue, 21 Feb 2006 18:36:17 +0800 Subject: [PATCH] ipw2100: add radiotap headers to packtes captured in monitor mode Signed-off-by: Stefan Rompf Signed-off-by: Andrea Merello Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 95 +++++++++++++++++++++++++++++++++++++----- drivers/net/wireless/ipw2100.h | 4 ++ 2 files changed, 88 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 84f63876bf7..d429fd576a6 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -2390,15 +2390,6 @@ static void isr_rx(struct ipw2100_priv *priv, int i, IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); return; } -#ifdef CONFIG_IPW2100_MONITOR - if (unlikely(priv->ieee->iw_mode == IW_MODE_MONITOR && - priv->config & CFG_CRC_CHECK && - status->flags & IPW_STATUS_FLAG_CRC_ERROR)) { - IPW_DEBUG_RX("CRC error in packet. Dropping.\n"); - priv->ieee->stats.rx_errors++; - return; - } -#endif if (unlikely(priv->ieee->iw_mode != IW_MODE_MONITOR && !(priv->status & STATUS_ASSOCIATED))) { @@ -2446,6 +2437,88 @@ static void isr_rx(struct ipw2100_priv *priv, int i, priv->rx_queue.drv[i].host_addr = packet->dma_addr; } +#ifdef CONFIG_IPW2100_MONITOR + +static void isr_rx_monitor(struct ipw2100_priv *priv, int i, + struct ieee80211_rx_stats *stats) +{ + struct ipw2100_status *status = &priv->status_queue.drv[i]; + struct ipw2100_rx_packet *packet = &priv->rx_buffers[i]; + + IPW_DEBUG_RX("Handler...\n"); + + /* Magic struct that slots into the radiotap header -- no reason + * to build this manually element by element, we can write it much + * more efficiently than we can parse it. ORDER MATTERS HERE */ + struct ipw_rt_hdr { + struct ieee80211_radiotap_header rt_hdr; + s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ + } *ipw_rt; + + if (unlikely(status->frame_size > skb_tailroom(packet->skb) - sizeof(struct ipw_rt_hdr))) { + IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!" + " Dropping.\n", + priv->net_dev->name, + status->frame_size, skb_tailroom(packet->skb)); + priv->ieee->stats.rx_errors++; + return; + } + + if (unlikely(!netif_running(priv->net_dev))) { + priv->ieee->stats.rx_errors++; + priv->wstats.discard.misc++; + IPW_DEBUG_DROP("Dropping packet while interface is not up.\n"); + return; + } + + if (unlikely(priv->config & CFG_CRC_CHECK && + status->flags & IPW_STATUS_FLAG_CRC_ERROR)) { + IPW_DEBUG_RX("CRC error in packet. Dropping.\n"); + priv->ieee->stats.rx_errors++; + return; + } + + pci_unmap_single(priv->pci_dev, + packet->dma_addr, + sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); + memmove(packet->skb->data + sizeof(struct ipw_rt_hdr), + packet->skb->data, status->frame_size); + + ipw_rt = (struct ipw_rt_hdr *) packet->skb->data; + + ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; + ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ + ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total header+data */ + + ipw_rt->rt_hdr.it_present = 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL; + + ipw_rt->rt_dbmsignal = status->rssi + IPW2100_RSSI_TO_DBM; + + skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr)); + + if (!ieee80211_rx(priv->ieee, packet->skb, stats)) { + priv->ieee->stats.rx_errors++; + + /* ieee80211_rx failed, so it didn't free the SKB */ + dev_kfree_skb_any(packet->skb); + packet->skb = NULL; + } + + /* We need to allocate a new SKB and attach it to the RDB. */ + if (unlikely(ipw2100_alloc_skb(priv, packet))) { + IPW_DEBUG_WARNING( + "%s: Unable to allocate SKB onto RBD ring - disabling " + "adapter.\n", priv->net_dev->name); + /* TODO: schedule adapter shutdown */ + IPW_DEBUG_INFO("TODO: Shutdown adapter...\n"); + } + + /* Update the RDB entry */ + priv->rx_queue.drv[i].host_addr = packet->dma_addr; +} + +#endif + static int ipw2100_corruption_check(struct ipw2100_priv *priv, int i) { struct ipw2100_status *status = &priv->status_queue.drv[i]; @@ -2577,7 +2650,7 @@ static void __ipw2100_rx_process(struct ipw2100_priv *priv) case P8023_DATA_VAL: #ifdef CONFIG_IPW2100_MONITOR if (priv->ieee->iw_mode == IW_MODE_MONITOR) { - isr_rx(priv, i, &stats); + isr_rx_monitor(priv, i, &stats); break; } #endif @@ -3882,7 +3955,7 @@ static int ipw2100_switch_mode(struct ipw2100_priv *priv, u32 mode) #ifdef CONFIG_IPW2100_MONITOR case IW_MODE_MONITOR: priv->last_mode = priv->ieee->iw_mode; - priv->net_dev->type = ARPHRD_IEEE80211; + priv->net_dev->type = ARPHRD_IEEE80211_RADIOTAP; break; #endif /* CONFIG_IPW2100_MONITOR */ } diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index 948d426fcf9..6f0b40f96ab 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h @@ -41,6 +41,10 @@ #include +#ifdef CONFIG_IPW2100_MONITOR +#include +#endif + #include struct ipw2100_priv; -- cgit v1.2.3 From cae1629515cf6d166fa20657e68b75619d563280 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 21 Feb 2006 18:41:14 +0800 Subject: [PATCH] ipw2100: Fix radiotap code gcc warning Fix gcc warning: ipw2100.c:2460: ISO C90 forbids mixed declarations and code Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index d429fd576a6..b0e23a88250 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -2445,8 +2445,6 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i, struct ipw2100_status *status = &priv->status_queue.drv[i]; struct ipw2100_rx_packet *packet = &priv->rx_buffers[i]; - IPW_DEBUG_RX("Handler...\n"); - /* Magic struct that slots into the radiotap header -- no reason * to build this manually element by element, we can write it much * more efficiently than we can parse it. ORDER MATTERS HERE */ @@ -2455,11 +2453,15 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i, s8 rt_dbmsignal; /* signal in dbM, kluged to signed */ } *ipw_rt; - if (unlikely(status->frame_size > skb_tailroom(packet->skb) - sizeof(struct ipw_rt_hdr))) { + IPW_DEBUG_RX("Handler...\n"); + + if (unlikely(status->frame_size > skb_tailroom(packet->skb) - + sizeof(struct ipw_rt_hdr))) { IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!" " Dropping.\n", priv->net_dev->name, - status->frame_size, skb_tailroom(packet->skb)); + status->frame_size, + skb_tailroom(packet->skb)); priv->ieee->stats.rx_errors++; return; } @@ -2478,8 +2480,7 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i, return; } - pci_unmap_single(priv->pci_dev, - packet->dma_addr, + pci_unmap_single(priv->pci_dev, packet->dma_addr, sizeof(struct ipw2100_rx), PCI_DMA_FROMDEVICE); memmove(packet->skb->data + sizeof(struct ipw_rt_hdr), packet->skb->data, status->frame_size); @@ -2488,7 +2489,7 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i, ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ - ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total header+data */ + ipw_rt->rt_hdr.it_len = sizeof(struct ipw_rt_hdr); /* total hdr+data */ ipw_rt->rt_hdr.it_present = 1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL; -- cgit v1.2.3 From 752e377bfdad61482e39cafedb3a6bb1b5bb0289 Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 28 Feb 2006 07:20:54 +0800 Subject: [PATCH] ipw2100: semaphore to mutexes conversion semaphore to mutexes conversion. the conversion was generated via scripts, and the result was validated automatically via a script as well. build-tested. Signed-off-by: Ingo Molnar Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 119 +++++++++++++++++++++-------------------- drivers/net/wireless/ipw2100.h | 4 +- 2 files changed, 62 insertions(+), 61 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index b0e23a88250..54437206f31 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -194,6 +194,7 @@ static struct ipw2100_fw ipw2100_firmware; #endif #include +#include module_param(debug, int, 0444); module_param(mode, int, 0444); module_param(channel, int, 0444); @@ -1418,7 +1419,7 @@ static int ipw2100_enable_adapter(struct ipw2100_priv *priv) if (priv->status & STATUS_ENABLED) return 0; - down(&priv->adapter_sem); + mutex_lock(&priv->adapter_mutex); if (rf_kill_active(priv)) { IPW_DEBUG_HC("Command aborted due to RF kill active.\n"); @@ -1444,7 +1445,7 @@ static int ipw2100_enable_adapter(struct ipw2100_priv *priv) } fail_up: - up(&priv->adapter_sem); + mutex_unlock(&priv->adapter_mutex); return err; } @@ -1576,7 +1577,7 @@ static int ipw2100_disable_adapter(struct ipw2100_priv *priv) cancel_delayed_work(&priv->hang_check); } - down(&priv->adapter_sem); + mutex_lock(&priv->adapter_mutex); err = ipw2100_hw_send_command(priv, &cmd); if (err) { @@ -1595,7 +1596,7 @@ static int ipw2100_disable_adapter(struct ipw2100_priv *priv) IPW_DEBUG_INFO("TODO: implement scan state machine\n"); fail_up: - up(&priv->adapter_sem); + mutex_unlock(&priv->adapter_mutex); return err; } @@ -1888,7 +1889,7 @@ static void ipw2100_reset_adapter(struct ipw2100_priv *priv) priv->status |= STATUS_RESET_PENDING; spin_unlock_irqrestore(&priv->low_lock, flags); - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); /* stop timed checks so that they don't interfere with reset */ priv->stop_hang_check = 1; cancel_delayed_work(&priv->hang_check); @@ -1898,7 +1899,7 @@ static void ipw2100_reset_adapter(struct ipw2100_priv *priv) wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); ipw2100_up(priv, 0); - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); } @@ -4212,7 +4213,7 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio) IPW_DEBUG_RF_KILL("Manual SW RF Kill set to: RADIO %s\n", disable_radio ? "OFF" : "ON"); - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (disable_radio) { priv->status |= STATUS_RF_KILL_SW; @@ -4230,7 +4231,7 @@ static int ipw_radio_kill_sw(struct ipw2100_priv *priv, int disable_radio) schedule_reset(priv); } - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return 1; } @@ -5534,7 +5535,7 @@ static void shim__set_security(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); int i, force_update = 0; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) goto done; @@ -5607,7 +5608,7 @@ static void shim__set_security(struct net_device *dev, if (!(priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) ipw2100_configure_security(priv, 0); done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); } static int ipw2100_adapter_setup(struct ipw2100_priv *priv) @@ -5731,7 +5732,7 @@ static int ipw2100_set_address(struct net_device *dev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); priv->config |= CFG_CUSTOM_MAC; memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); @@ -5741,12 +5742,12 @@ static int ipw2100_set_address(struct net_device *dev, void *p) goto done; priv->reset_backoff = 0; - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); ipw2100_reset_adapter(priv); return 0; done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -6089,8 +6090,8 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev, strcpy(priv->nick, "ipw2100"); spin_lock_init(&priv->low_lock); - sema_init(&priv->action_sem, 1); - sema_init(&priv->adapter_sem, 1); + mutex_init(&priv->action_mutex); + mutex_init(&priv->adapter_mutex); init_waitqueue_head(&priv->wait_command_queue); @@ -6255,7 +6256,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, * member to call a function that then just turns and calls ipw2100_up. * net_dev->init is called after name allocation but before the * notifier chain is called */ - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); err = register_netdev(dev); if (err) { printk(KERN_WARNING DRV_NAME @@ -6291,12 +6292,12 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, priv->status |= STATUS_INITIALIZED; - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return 0; fail_unlock: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); fail: if (dev) { @@ -6336,7 +6337,7 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) struct net_device *dev; if (priv) { - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); priv->status &= ~STATUS_INITIALIZED; @@ -6351,9 +6352,9 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) /* Take down the hardware */ ipw2100_down(priv); - /* Release the semaphore so that the network subsystem can + /* Release the mutex so that the network subsystem can * complete any needed calls into the driver... */ - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); /* Unregister the device first - this results in close() * being called if the device is open. If we free storage @@ -6392,7 +6393,7 @@ static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state) IPW_DEBUG_INFO("%s: Going into suspend...\n", dev->name); - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (priv->status & STATUS_INITIALIZED) { /* Take down the device; powers it off, etc. */ ipw2100_down(priv); @@ -6405,7 +6406,7 @@ static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state) pci_disable_device(pci_dev); pci_set_power_state(pci_dev, PCI_D3hot); - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return 0; } @@ -6419,7 +6420,7 @@ static int ipw2100_resume(struct pci_dev *pci_dev) if (IPW2100_PM_DISABLED) return 0; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); IPW_DEBUG_INFO("%s: Coming out of suspend...\n", dev->name); @@ -6445,7 +6446,7 @@ static int ipw2100_resume(struct pci_dev *pci_dev) if (!(priv->status & STATUS_RF_KILL_SW)) ipw2100_up(priv, 0); - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return 0; } @@ -6609,7 +6610,7 @@ static int ipw2100_wx_set_freq(struct net_device *dev, if (priv->ieee->iw_mode == IW_MODE_INFRA) return -EOPNOTSUPP; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -6640,7 +6641,7 @@ static int ipw2100_wx_set_freq(struct net_device *dev, } done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -6681,7 +6682,7 @@ static int ipw2100_wx_set_mode(struct net_device *dev, if (wrqu->mode == priv->ieee->iw_mode) return 0; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -6704,7 +6705,7 @@ static int ipw2100_wx_set_mode(struct net_device *dev, } done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -6886,7 +6887,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev, if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) return -EINVAL; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -6915,7 +6916,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev, wrqu->ap_addr.sa_data[5] & 0xff); done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -6951,7 +6952,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev, int length = 0; int err = 0; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -6988,7 +6989,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev, err = ipw2100_set_essid(priv, essid, length, 0); done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -7069,7 +7070,7 @@ static int ipw2100_wx_set_rate(struct net_device *dev, u32 rate; int err = 0; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -7096,7 +7097,7 @@ static int ipw2100_wx_set_rate(struct net_device *dev, IPW_DEBUG_WX("SET Rate -> %04X \n", rate); done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -7116,7 +7117,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev, return 0; } - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -7148,7 +7149,7 @@ static int ipw2100_wx_get_rate(struct net_device *dev, IPW_DEBUG_WX("GET Rate -> %d \n", wrqu->bitrate.value); done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -7163,7 +7164,7 @@ static int ipw2100_wx_set_rts(struct net_device *dev, if (wrqu->rts.fixed == 0) return -EINVAL; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -7183,7 +7184,7 @@ static int ipw2100_wx_set_rts(struct net_device *dev, IPW_DEBUG_WX("SET RTS Threshold -> 0x%08X \n", value); done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -7234,7 +7235,7 @@ static int ipw2100_wx_set_txpow(struct net_device *dev, value = wrqu->txpower.value; } - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -7245,7 +7246,7 @@ static int ipw2100_wx_set_txpow(struct net_device *dev, IPW_DEBUG_WX("SET TX Power -> %d \n", value); done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -7337,7 +7338,7 @@ static int ipw2100_wx_set_retry(struct net_device *dev, if (!(wrqu->retry.flags & IW_RETRY_LIMIT)) return 0; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -7364,7 +7365,7 @@ static int ipw2100_wx_set_retry(struct net_device *dev, IPW_DEBUG_WX("SET Both Retry Limits -> %d \n", wrqu->retry.value); done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -7407,7 +7408,7 @@ static int ipw2100_wx_set_scan(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); int err = 0; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -7422,7 +7423,7 @@ static int ipw2100_wx_set_scan(struct net_device *dev, } done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -7472,7 +7473,7 @@ static int ipw2100_wx_set_power(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); int err = 0; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -7505,7 +7506,7 @@ static int ipw2100_wx_set_power(struct net_device *dev, IPW_DEBUG_WX("SET Power Management Mode -> 0x%02X\n", priv->power_mode); done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -7809,7 +7810,7 @@ static int ipw2100_wx_set_promisc(struct net_device *dev, int enable = (parms[0] > 0); int err = 0; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -7827,7 +7828,7 @@ static int ipw2100_wx_set_promisc(struct net_device *dev, err = ipw2100_switch_mode(priv, priv->last_mode); } done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -7850,7 +7851,7 @@ static int ipw2100_wx_set_powermode(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); int err = 0, mode = *(int *)extra; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -7862,7 +7863,7 @@ static int ipw2100_wx_set_powermode(struct net_device *dev, if (priv->power_mode != mode) err = ipw2100_set_power_mode(priv, mode); done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -7914,7 +7915,7 @@ static int ipw2100_wx_set_preamble(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); int err, mode = *(int *)extra; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -7932,7 +7933,7 @@ static int ipw2100_wx_set_preamble(struct net_device *dev, err = ipw2100_system_config(priv, 0); done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -7962,7 +7963,7 @@ static int ipw2100_wx_set_crc_check(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); int err, mode = *(int *)extra; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { err = -EIO; goto done; @@ -7979,7 +7980,7 @@ static int ipw2100_wx_set_crc_check(struct net_device *dev, err = 0; done: - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); return err; } @@ -8284,11 +8285,11 @@ static void ipw2100_wx_event_work(struct ipw2100_priv *priv) if (priv->status & STATUS_STOPPING) return; - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); IPW_DEBUG_WX("enter\n"); - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); wrqu.ap_addr.sa_family = ARPHRD_ETHER; @@ -8311,7 +8312,7 @@ static void ipw2100_wx_event_work(struct ipw2100_priv *priv) if (!(priv->status & STATUS_ASSOCIATED)) { IPW_DEBUG_WX("Configuring ESSID\n"); - down(&priv->action_sem); + mutex_lock(&priv->action_mutex); /* This is a disassociation event, so kick the firmware to * look for another AP */ if (priv->config & CFG_STATIC_ESSID) @@ -8319,7 +8320,7 @@ static void ipw2100_wx_event_work(struct ipw2100_priv *priv) 0); else ipw2100_set_essid(priv, NULL, 0, 0); - up(&priv->action_sem); + mutex_unlock(&priv->action_mutex); } wireless_send_event(priv->net_dev, SIOCGIWAP, &wrqu, NULL); diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index 6f0b40f96ab..7d390f74160 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h @@ -594,8 +594,8 @@ struct ipw2100_priv { int inta_other; spinlock_t low_lock; - struct semaphore action_sem; - struct semaphore adapter_sem; + struct mutex action_mutex; + struct mutex adapter_mutex; wait_queue_head_t wait_command_queue; }; -- cgit v1.2.3 From 3234eeec18315356166cd89bd93fc4630192eece Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 28 Feb 2006 08:38:07 +0800 Subject: [PATCH] ipw2100: move mutex.h include from ipw2100.c to ipw2100.h Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 1 - drivers/net/wireless/ipw2100.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 54437206f31..e1bba481982 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -194,7 +194,6 @@ static struct ipw2100_fw ipw2100_firmware; #endif #include -#include module_param(debug, int, 0444); module_param(mode, int, 0444); module_param(channel, int, 0444); diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2100.h index 7d390f74160..55b7227198d 100644 --- a/drivers/net/wireless/ipw2100.h +++ b/drivers/net/wireless/ipw2100.h @@ -46,6 +46,7 @@ #endif #include +#include struct ipw2100_priv; struct ipw2100_tx_packet; -- cgit v1.2.3 From cc8279f68c34c3f32b3a85f3103b0ad755c57846 Mon Sep 17 00:00:00 2001 From: Zhu Yi Date: Tue, 21 Feb 2006 18:46:15 +0800 Subject: [PATCH] ipw2100: Update version ipw2100 stamp to 1.2.2 Signed-off-by: Zhu Yi Signed-off-by: John W. Linville --- drivers/net/wireless/ipw2100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index e1bba481982..72335c8eb97 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -167,7 +167,7 @@ that only one external action is invoked at a time. #include "ipw2100.h" -#define IPW2100_VERSION "git-1.1.4" +#define IPW2100_VERSION "git-1.2.2" #define DRV_NAME "ipw2100" #define DRV_VERSION IPW2100_VERSION -- cgit v1.2.3 From 4a29cc2e503b33a1e96db4c3f9a94165f153f259 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Sun, 19 Mar 2006 13:21:12 -0800 Subject: [TG3]: 40-bit DMA workaround part 2 The 40-bit DMA workaround recently implemented for 5714, 5715, and 5780 needs to be expanded because there may be other tg3 devices behind the EPB Express to PCIX bridge in the 5780 class device. For example, some 4-port card or mother board designs have 5704 behind the 5714. All devices behind the EPB require the 40-bit DMA workaround. Thanks to Chris Elmquist again for reporting the problem and testing the patch. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 52 +++++++++++++++++++++++++++++++++++++++++++--------- drivers/net/tg3.h | 1 + 2 files changed, 44 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b8f1524da55..caf4102b54c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -9552,12 +9552,36 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } } - /* Find msi capability. */ + /* The EPB bridge inside 5714, 5715, and 5780 cannot support + * DMA addresses > 40-bit. This bridge may have other additional + * 57xx devices behind it in some 4-port NIC designs for example. + * Any tg3 device found behind the bridge will also need the 40-bit + * DMA workaround. + */ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { tp->tg3_flags2 |= TG3_FLG2_5780_CLASS; + tp->tg3_flags |= TG3_FLAG_40BIT_DMA_BUG; tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI); } + else { + struct pci_dev *bridge = NULL; + + do { + bridge = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_EPB, + bridge); + if (bridge && bridge->subordinate && + (bridge->subordinate->number <= + tp->pdev->bus->number) && + (bridge->subordinate->subordinate >= + tp->pdev->bus->number)) { + tp->tg3_flags |= TG3_FLAG_40BIT_DMA_BUG; + pci_dev_put(bridge); + break; + } + } while (bridge); + } /* Initialize misc host control in PCI block. */ tp->misc_host_ctrl |= (misc_ctrl_reg & @@ -10303,7 +10327,14 @@ static int __devinit tg3_test_dma(struct tg3 *tp) GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { u32 ccval = (tr32(TG3PCI_CLOCK_CTRL) & 0x1f); - if (ccval == 0x6 || ccval == 0x7) + /* If the 5704 is behind the EPB bridge, we can + * do the less restrictive ONE_DMA workaround for + * better performance. + */ + if ((tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG) && + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) + tp->dma_rwctrl |= 0x8000; + else if (ccval == 0x6 || ccval == 0x7) tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA; /* Set bit 23 to enable PCIX hw bug fix */ @@ -10759,19 +10790,20 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_iounmap; } - /* 5714, 5715 and 5780 cannot support DMA addresses > 40-bit. + /* The EPB bridge inside 5714, 5715, and 5780 and any + * device behind the EPB cannot support DMA addresses > 40-bit. * On 64-bit systems with IOMMU, use 40-bit dma_mask. * On 64-bit systems without IOMMU, use 64-bit dma_mask and * do DMA address check in tg3_start_xmit(). */ - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) { + if (tp->tg3_flags2 & TG3_FLG2_IS_5788) + persist_dma_mask = dma_mask = DMA_32BIT_MASK; + else if (tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG) { persist_dma_mask = dma_mask = DMA_40BIT_MASK; #ifdef CONFIG_HIGHMEM dma_mask = DMA_64BIT_MASK; #endif - } else if (tp->tg3_flags2 & TG3_FLG2_IS_5788) - persist_dma_mask = dma_mask = DMA_32BIT_MASK; - else + } else persist_dma_mask = dma_mask = DMA_64BIT_MASK; /* Configure DMA attributes. */ @@ -10908,8 +10940,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, (tp->tg3_flags & TG3_FLAG_SPLIT_MODE) != 0, (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0, (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0); - printk(KERN_INFO "%s: dma_rwctrl[%08x]\n", - dev->name, tp->dma_rwctrl); + printk(KERN_INFO "%s: dma_rwctrl[%08x] dma_mask[%d-bit]\n", + dev->name, tp->dma_rwctrl, + (pdev->dma_mask == DMA_32BIT_MASK) ? 32 : + (((u64) pdev->dma_mask == DMA_40BIT_MASK) ? 40 : 64)); return 0; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 7f4b7f6ac40..7e3b613afb2 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2163,6 +2163,7 @@ struct tg3 { #define TG3_FLAG_10_100_ONLY 0x01000000 #define TG3_FLAG_PAUSE_AUTONEG 0x02000000 #define TG3_FLAG_IN_RESET_TASK 0x04000000 +#define TG3_FLAG_40BIT_DMA_BUG 0x08000000 #define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 #define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000 #define TG3_FLAG_SPLIT_MODE 0x40000000 -- cgit v1.2.3 From 72b845e04e99298e5179b31e8de16afed52a2627 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 14 Mar 2006 14:11:48 -0800 Subject: [TG3]: Do not try to access NIC_SRAM_DATA_SIG on Sun parts. Sun does't put an SEEPROM behind the tigon3 chip, among other things, so accesses to these areas just give bus timeouts. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index caf4102b54c..31a16fa6755 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -9097,6 +9097,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) tp->phy_id = PHY_ID_INVALID; tp->led_ctrl = LED_CTRL_MODE_PHY_1; + /* Do not even try poking around in here on Sun parts. */ + if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) + return; + tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); if (val == NIC_SRAM_DATA_SIG_MAGIC) { u32 nic_cfg, led_cfg; -- cgit v1.2.3 From 489447380a2921ec0e9154f773c44ab3167ede4b Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Thu, 19 Jan 2006 17:56:29 +0000 Subject: [PATCH] handle errors returned by platform_get_irq*() platform_get_irq*() now returns on -ENXIO when the resource cannot be found. Ensure all users of platform_get_irq*() handle this error appropriately. Signed-off-by: David Vrabel Signed-off-by: Greg Kroah-Hartman --- drivers/net/arm/am79c961a.c | 4 +++- drivers/net/fs_enet/mac-fcc.c | 2 ++ drivers/net/fs_enet/mac-fec.c | 2 ++ drivers/net/fs_enet/mac-scc.c | 2 ++ drivers/net/gianfar.c | 4 ++++ drivers/net/smc91x.c | 4 ++++ 6 files changed, 17 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 53e3afc1b7b..09d5c3f2698 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -696,7 +696,9 @@ static int __init am79c961_probe(struct platform_device *pdev) dev->base_addr = res->start; dev->irq = platform_get_irq(pdev, 0); - ret = -ENODEV; + ret = -ENODEV; + if (dev->irq < 0) + goto nodev; if (!request_region(dev->base_addr, 0x18, dev->name)) goto nodev; diff --git a/drivers/net/fs_enet/mac-fcc.c b/drivers/net/fs_enet/mac-fcc.c index e67b1d06611..95e2bb8dd7b 100644 --- a/drivers/net/fs_enet/mac-fcc.c +++ b/drivers/net/fs_enet/mac-fcc.c @@ -118,6 +118,8 @@ static int do_pd_setup(struct fs_enet_private *fep) /* Fill out IRQ field */ fep->interrupt = platform_get_irq(pdev, 0); + if (fep->interrupt < 0) + return -EINVAL; /* Attach the memory for the FCC Parameter RAM */ r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fcc_pram"); diff --git a/drivers/net/fs_enet/mac-fec.c b/drivers/net/fs_enet/mac-fec.c index 2e8f4446969..3dad69dfdb2 100644 --- a/drivers/net/fs_enet/mac-fec.c +++ b/drivers/net/fs_enet/mac-fec.c @@ -144,6 +144,8 @@ static int do_pd_setup(struct fs_enet_private *fep) /* Fill out IRQ field */ fep->interrupt = platform_get_irq_byname(pdev,"interrupt"); + if (fep->interrupt < 0) + return -EINVAL; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); fep->fec.fecp =(void*)r->start; diff --git a/drivers/net/fs_enet/mac-scc.c b/drivers/net/fs_enet/mac-scc.c index a3897fda71f..a772b286f96 100644 --- a/drivers/net/fs_enet/mac-scc.c +++ b/drivers/net/fs_enet/mac-scc.c @@ -118,6 +118,8 @@ static int do_pd_setup(struct fs_enet_private *fep) /* Fill out IRQ field */ fep->interrupt = platform_get_irq_byname(pdev, "interrupt"); + if (fep->interrupt < 0) + return -EINVAL; r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); fep->scc.sccp = (void *)r->start; diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index 0e8e3fcde9f..771e25d8c41 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -193,8 +193,12 @@ static int gfar_probe(struct platform_device *pdev) priv->interruptTransmit = platform_get_irq_byname(pdev, "tx"); priv->interruptReceive = platform_get_irq_byname(pdev, "rx"); priv->interruptError = platform_get_irq_byname(pdev, "error"); + if (priv->interruptTransmit < 0 || priv->interruptReceive < 0 || priv->interruptError < 0) + goto regs_fail; } else { priv->interruptTransmit = platform_get_irq(pdev, 0); + if (priv->interruptTransmit < 0) + goto regs_fail; } /* get a pointer to the register memory */ diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 7ec08127c9d..75e9b3b910c 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -2221,6 +2221,10 @@ static int smc_drv_probe(struct platform_device *pdev) ndev->dma = (unsigned char)-1; ndev->irq = platform_get_irq(pdev, 0); + if (ndev->irq < 0) { + ret = -ENODEV; + goto out_free_netdev; + } ret = smc_request_attrib(pdev); if (ret) -- cgit v1.2.3 From da81817fbd744ce70983f1d3c61841265003c7f4 Mon Sep 17 00:00:00 2001 From: Eugene Teo Date: Wed, 15 Mar 2006 14:57:19 -0800 Subject: [PATCH] USB: Fix irda-usb use after use Don't read from free'd memory after calling netif_rx(). docopy is used as a boolean (0 and 1) so unsigned int is sufficient. Coverity bug #928 Signed-off-by: Eugene Teo Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- drivers/net/irda/irda-usb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index 8936058a3cc..6e2ec56cde0 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -740,7 +740,7 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) struct sk_buff *newskb; struct sk_buff *dataskb; struct urb *next_urb; - int docopy; + unsigned int len, docopy; IRDA_DEBUG(2, "%s(), len=%d\n", __FUNCTION__, urb->actual_length); @@ -851,10 +851,11 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs) dataskb->dev = self->netdev; dataskb->mac.raw = dataskb->data; dataskb->protocol = htons(ETH_P_IRDA); + len = dataskb->len; netif_rx(dataskb); /* Keep stats up to date */ - self->stats.rx_bytes += dataskb->len; + self->stats.rx_bytes += len; self->stats.rx_packets++; self->netdev->last_rx = jiffies; -- cgit v1.2.3 From d4d2c558fd3e1f5e386b153f194aa8f0be496c77 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 17:47:20 -0800 Subject: [TG3]: Add support for 5714S and 5715S Add support for 5714S and 5715S. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 6c6c5498899..b0de6b2754c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -223,8 +223,12 @@ static struct pci_device_id tg3_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5715S, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S, @@ -2680,6 +2684,12 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) err |= tg3_readphy(tp, MII_BMSR, &bmsr); err |= tg3_readphy(tp, MII_BMSR, &bmsr); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) { + if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP) + bmsr |= BMSR_LSTATUS; + else + bmsr &= ~BMSR_LSTATUS; + } err |= tg3_readphy(tp, MII_BMCR, &bmcr); @@ -2748,6 +2758,13 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset) bmcr = new_bmcr; err |= tg3_readphy(tp, MII_BMSR, &bmsr); err |= tg3_readphy(tp, MII_BMSR, &bmsr); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == + ASIC_REV_5714) { + if (tr32(MAC_TX_STATUS) & TX_STATUS_LINK_UP) + bmsr |= BMSR_LSTATUS; + else + bmsr &= ~BMSR_LSTATUS; + } tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT; } } @@ -5585,6 +5602,9 @@ static int tg3_reset_hw(struct tg3 *tp) tg3_abort_hw(tp, 1); } + if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) + tg3_phy_reset(tp); + err = tg3_chip_reset(tp); if (err) return err; @@ -6097,6 +6117,17 @@ static int tg3_reset_hw(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_HW_AUTONEG; } + if ((tp->tg3_flags2 & TG3_FLG2_MII_SERDES) && + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) { + u32 tmp; + + tmp = tr32(SERDES_RX_CTRL); + tw32(SERDES_RX_CTRL, tmp | SERDES_RX_SIG_DETECT); + tp->grc_local_ctrl &= ~GRC_LCLCTRL_USE_EXT_SIG_DETECT; + tp->grc_local_ctrl |= GRC_LCLCTRL_USE_SIG_DETECT; + tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); + } + err = tg3_setup_phy(tp, 1); if (err) return err; @@ -6476,7 +6507,9 @@ static int tg3_open(struct net_device *dev) if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) && (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_AX) && - (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_BX)) { + (GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5750_BX) && + !((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714) && + (tp->pdev_peer == tp->pdev))) { /* All MSI supporting chips should support tagged * status. Assert that this is the case. */ -- cgit v1.2.3 From 4e3a7aaa28db952392814f889dfbd25672266d29 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 17:47:44 -0800 Subject: [TG3]: Enable TSO by default Enable TSO by default on newer chips that support TSO in hardware. Leave TSO off by default on older chips that do firmware TSO because performance is slightly lower. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b0de6b2754c..7deebd74223 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10881,11 +10881,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE; } - /* TSO is off by default, user can enable using ethtool. */ -#if 0 - if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) + /* TSO is on by default on chips that support hardware TSO. + * Firmware TSO on older chips gives lower performance, so it + * is off by default, but can be enabled using ethtool. + */ + if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) dev->features |= NETIF_F_TSO; -#endif #endif -- cgit v1.2.3 From bc1c756741b065cfebf850e4164c0e2aae9d527f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 17:48:03 -0800 Subject: [TG3]: Support shutdown WoL. Support WoL during shutdown by calling tg3_set_power_state(tp, PCI_D3hot) during tg3_close(). Change the power state parameter to pci_power_t type and use constants defined in pci.h. Certain ethtool operations cannot be performed after tg3_close() because the device will go to low power state. Add return -EAGAIN in such cases where appropriate. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 52 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 7deebd74223..01fed17d076 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1042,9 +1042,11 @@ static void tg3_frob_aux_power(struct tg3 *tp) struct net_device *dev_peer; dev_peer = pci_get_drvdata(tp->pdev_peer); + /* remove_one() may have been run on the peer. */ if (!dev_peer) - BUG(); - tp_peer = netdev_priv(dev_peer); + tp_peer = tp; + else + tp_peer = netdev_priv(dev_peer); } if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) != 0 || @@ -1135,7 +1137,7 @@ static int tg3_halt_cpu(struct tg3 *, u32); static int tg3_nvram_lock(struct tg3 *); static void tg3_nvram_unlock(struct tg3 *); -static int tg3_set_power_state(struct tg3 *tp, int state) +static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) { u32 misc_host_ctrl; u16 power_control, power_caps; @@ -1154,7 +1156,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state) power_control |= PCI_PM_CTRL_PME_STATUS; power_control &= ~(PCI_PM_CTRL_STATE_MASK); switch (state) { - case 0: + case PCI_D0: power_control |= 0; pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, @@ -1167,15 +1169,15 @@ static int tg3_set_power_state(struct tg3 *tp, int state) return 0; - case 1: + case PCI_D1: power_control |= 1; break; - case 2: + case PCI_D2: power_control |= 2; break; - case 3: + case PCI_D3hot: power_control |= 3; break; @@ -6206,7 +6208,7 @@ static int tg3_init_hw(struct tg3 *tp) int err; /* Force the chip into D0. */ - err = tg3_set_power_state(tp, 0); + err = tg3_set_power_state(tp, PCI_D0); if (err) goto out; @@ -6493,6 +6495,10 @@ static int tg3_open(struct net_device *dev) tg3_full_lock(tp, 0); + err = tg3_set_power_state(tp, PCI_D0); + if (err) + return err; + tg3_disable_ints(tp); tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE; @@ -6872,7 +6878,6 @@ static int tg3_close(struct net_device *dev) tp->tg3_flags &= ~(TG3_FLAG_INIT_COMPLETE | TG3_FLAG_GOT_SERDES_FLOWCTL); - netif_carrier_off(tp->dev); tg3_full_unlock(tp); @@ -6889,6 +6894,10 @@ static int tg3_close(struct net_device *dev) tg3_free_consistent(tp); + tg3_set_power_state(tp, PCI_D3hot); + + netif_carrier_off(tp->dev); + return 0; } @@ -7207,6 +7216,9 @@ static void tg3_get_regs(struct net_device *dev, memset(p, 0, TG3_REGDUMP_LEN); + if (tp->link_config.phy_is_low_power) + return; + tg3_full_lock(tp, 0); #define __GET_REG32(reg) (*(p)++ = tr32(reg)) @@ -7281,6 +7293,9 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *pd; u32 i, offset, len, val, b_offset, b_count; + if (tp->link_config.phy_is_low_power) + return -EAGAIN; + offset = eeprom->offset; len = eeprom->len; eeprom->len = 0; @@ -7342,6 +7357,9 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u32 offset, len, b_offset, odd_len, start, end; u8 *buf; + if (tp->link_config.phy_is_low_power) + return -EAGAIN; + if (eeprom->magic != TG3_EEPROM_MAGIC) return -EINVAL; @@ -8262,6 +8280,9 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, { struct tg3 *tp = netdev_priv(dev); + if (tp->link_config.phy_is_low_power) + tg3_set_power_state(tp, PCI_D0); + memset(data, 0, sizeof(u64) * TG3_NUM_TEST); if (tg3_test_nvram(tp) != 0) { @@ -8319,6 +8340,9 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, tg3_full_unlock(tp); } + if (tp->link_config.phy_is_low_power) + tg3_set_power_state(tp, PCI_D3hot); + } static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) @@ -8338,6 +8362,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) break; /* We have no PHY */ + if (tp->link_config.phy_is_low_power) + return -EAGAIN; + spin_lock_bh(&tp->lock); err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval); spin_unlock_bh(&tp->lock); @@ -8354,6 +8381,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (tp->link_config.phy_is_low_power) + return -EAGAIN; + spin_lock_bh(&tp->lock); err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in); spin_unlock_bh(&tp->lock); @@ -9805,7 +9835,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3; /* Force the chip into D0. */ - err = tg3_set_power_state(tp, 0); + err = tg3_set_power_state(tp, PCI_D0); if (err) { printk(KERN_ERR PFX "(%s) transition to D0 failed\n", pci_name(tp->pdev)); @@ -11078,7 +11108,7 @@ static int tg3_resume(struct pci_dev *pdev) pci_restore_state(tp->pdev); - err = tg3_set_power_state(tp, 0); + err = tg3_set_power_state(tp, PCI_D0); if (err) return err; -- cgit v1.2.3 From 2e2e4f5c996d577383c5cb584b153b39f4961155 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 17:48:18 -0800 Subject: [TG3]: Update version and reldate Update version to 3.50. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 01fed17d076..994658d26b8 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -69,8 +69,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.49" -#define DRV_MODULE_RELDATE "Feb 2, 2006" +#define DRV_MODULE_VERSION "3.50" +#define DRV_MODULE_RELDATE "Feb 4, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3 From 6b39777c5924b9db2406c5769a044da383782d0e Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 17:48:32 -0800 Subject: [BNX2]: Reduce register test size Eliminate some of the registers in ethtool register test to reduce driver size. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 254 ----------------------------------------------------- 1 file changed, 254 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index b787b6582e5..4be21b8501b 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3506,74 +3506,9 @@ bnx2_test_registers(struct bnx2 *bp) { 0x0c00, 0, 0x00000000, 0x00000001 }, { 0x0c04, 0, 0x00000000, 0x03ff0001 }, { 0x0c08, 0, 0x0f0ff073, 0x00000000 }, - { 0x0c0c, 0, 0x00ffffff, 0x00000000 }, - { 0x0c30, 0, 0x00000000, 0xffffffff }, - { 0x0c34, 0, 0x00000000, 0xffffffff }, - { 0x0c38, 0, 0x00000000, 0xffffffff }, - { 0x0c3c, 0, 0x00000000, 0xffffffff }, - { 0x0c40, 0, 0x00000000, 0xffffffff }, - { 0x0c44, 0, 0x00000000, 0xffffffff }, - { 0x0c48, 0, 0x00000000, 0x0007ffff }, - { 0x0c4c, 0, 0x00000000, 0xffffffff }, - { 0x0c50, 0, 0x00000000, 0xffffffff }, - { 0x0c54, 0, 0x00000000, 0xffffffff }, - { 0x0c58, 0, 0x00000000, 0xffffffff }, - { 0x0c5c, 0, 0x00000000, 0xffffffff }, - { 0x0c60, 0, 0x00000000, 0xffffffff }, - { 0x0c64, 0, 0x00000000, 0xffffffff }, - { 0x0c68, 0, 0x00000000, 0xffffffff }, - { 0x0c6c, 0, 0x00000000, 0xffffffff }, - { 0x0c70, 0, 0x00000000, 0xffffffff }, - { 0x0c74, 0, 0x00000000, 0xffffffff }, - { 0x0c78, 0, 0x00000000, 0xffffffff }, - { 0x0c7c, 0, 0x00000000, 0xffffffff }, - { 0x0c80, 0, 0x00000000, 0xffffffff }, - { 0x0c84, 0, 0x00000000, 0xffffffff }, - { 0x0c88, 0, 0x00000000, 0xffffffff }, - { 0x0c8c, 0, 0x00000000, 0xffffffff }, - { 0x0c90, 0, 0x00000000, 0xffffffff }, - { 0x0c94, 0, 0x00000000, 0xffffffff }, - { 0x0c98, 0, 0x00000000, 0xffffffff }, - { 0x0c9c, 0, 0x00000000, 0xffffffff }, - { 0x0ca0, 0, 0x00000000, 0xffffffff }, - { 0x0ca4, 0, 0x00000000, 0xffffffff }, - { 0x0ca8, 0, 0x00000000, 0x0007ffff }, - { 0x0cac, 0, 0x00000000, 0xffffffff }, - { 0x0cb0, 0, 0x00000000, 0xffffffff }, - { 0x0cb4, 0, 0x00000000, 0xffffffff }, - { 0x0cb8, 0, 0x00000000, 0xffffffff }, - { 0x0cbc, 0, 0x00000000, 0xffffffff }, - { 0x0cc0, 0, 0x00000000, 0xffffffff }, - { 0x0cc4, 0, 0x00000000, 0xffffffff }, - { 0x0cc8, 0, 0x00000000, 0xffffffff }, - { 0x0ccc, 0, 0x00000000, 0xffffffff }, - { 0x0cd0, 0, 0x00000000, 0xffffffff }, - { 0x0cd4, 0, 0x00000000, 0xffffffff }, - { 0x0cd8, 0, 0x00000000, 0xffffffff }, - { 0x0cdc, 0, 0x00000000, 0xffffffff }, - { 0x0ce0, 0, 0x00000000, 0xffffffff }, - { 0x0ce4, 0, 0x00000000, 0xffffffff }, - { 0x0ce8, 0, 0x00000000, 0xffffffff }, - { 0x0cec, 0, 0x00000000, 0xffffffff }, - { 0x0cf0, 0, 0x00000000, 0xffffffff }, - { 0x0cf4, 0, 0x00000000, 0xffffffff }, - { 0x0cf8, 0, 0x00000000, 0xffffffff }, - { 0x0cfc, 0, 0x00000000, 0xffffffff }, - { 0x0d00, 0, 0x00000000, 0xffffffff }, - { 0x0d04, 0, 0x00000000, 0xffffffff }, { 0x1000, 0, 0x00000000, 0x00000001 }, { 0x1004, 0, 0x00000000, 0x000f0001 }, - { 0x1044, 0, 0x00000000, 0xffc003ff }, - { 0x1080, 0, 0x00000000, 0x0001ffff }, - { 0x1084, 0, 0x00000000, 0xffffffff }, - { 0x1088, 0, 0x00000000, 0xffffffff }, - { 0x108c, 0, 0x00000000, 0xffffffff }, - { 0x1090, 0, 0x00000000, 0xffffffff }, - { 0x1094, 0, 0x00000000, 0xffffffff }, - { 0x1098, 0, 0x00000000, 0xffffffff }, - { 0x109c, 0, 0x00000000, 0xffffffff }, - { 0x10a0, 0, 0x00000000, 0xffffffff }, { 0x1408, 0, 0x01c00800, 0x00000000 }, { 0x149c, 0, 0x8000ffff, 0x00000000 }, @@ -3585,111 +3520,9 @@ bnx2_test_registers(struct bnx2 *bp) { 0x14c4, 0, 0x00003fff, 0x00000000 }, { 0x14cc, 0, 0x00000000, 0x00000001 }, { 0x14d0, 0, 0xffffffff, 0x00000000 }, - { 0x1500, 0, 0x00000000, 0xffffffff }, - { 0x1504, 0, 0x00000000, 0xffffffff }, - { 0x1508, 0, 0x00000000, 0xffffffff }, - { 0x150c, 0, 0x00000000, 0xffffffff }, - { 0x1510, 0, 0x00000000, 0xffffffff }, - { 0x1514, 0, 0x00000000, 0xffffffff }, - { 0x1518, 0, 0x00000000, 0xffffffff }, - { 0x151c, 0, 0x00000000, 0xffffffff }, - { 0x1520, 0, 0x00000000, 0xffffffff }, - { 0x1524, 0, 0x00000000, 0xffffffff }, - { 0x1528, 0, 0x00000000, 0xffffffff }, - { 0x152c, 0, 0x00000000, 0xffffffff }, - { 0x1530, 0, 0x00000000, 0xffffffff }, - { 0x1534, 0, 0x00000000, 0xffffffff }, - { 0x1538, 0, 0x00000000, 0xffffffff }, - { 0x153c, 0, 0x00000000, 0xffffffff }, - { 0x1540, 0, 0x00000000, 0xffffffff }, - { 0x1544, 0, 0x00000000, 0xffffffff }, - { 0x1548, 0, 0x00000000, 0xffffffff }, - { 0x154c, 0, 0x00000000, 0xffffffff }, - { 0x1550, 0, 0x00000000, 0xffffffff }, - { 0x1554, 0, 0x00000000, 0xffffffff }, - { 0x1558, 0, 0x00000000, 0xffffffff }, - { 0x1600, 0, 0x00000000, 0xffffffff }, - { 0x1604, 0, 0x00000000, 0xffffffff }, - { 0x1608, 0, 0x00000000, 0xffffffff }, - { 0x160c, 0, 0x00000000, 0xffffffff }, - { 0x1610, 0, 0x00000000, 0xffffffff }, - { 0x1614, 0, 0x00000000, 0xffffffff }, - { 0x1618, 0, 0x00000000, 0xffffffff }, - { 0x161c, 0, 0x00000000, 0xffffffff }, - { 0x1620, 0, 0x00000000, 0xffffffff }, - { 0x1624, 0, 0x00000000, 0xffffffff }, - { 0x1628, 0, 0x00000000, 0xffffffff }, - { 0x162c, 0, 0x00000000, 0xffffffff }, - { 0x1630, 0, 0x00000000, 0xffffffff }, - { 0x1634, 0, 0x00000000, 0xffffffff }, - { 0x1638, 0, 0x00000000, 0xffffffff }, - { 0x163c, 0, 0x00000000, 0xffffffff }, - { 0x1640, 0, 0x00000000, 0xffffffff }, - { 0x1644, 0, 0x00000000, 0xffffffff }, - { 0x1648, 0, 0x00000000, 0xffffffff }, - { 0x164c, 0, 0x00000000, 0xffffffff }, - { 0x1650, 0, 0x00000000, 0xffffffff }, - { 0x1654, 0, 0x00000000, 0xffffffff }, { 0x1800, 0, 0x00000000, 0x00000001 }, { 0x1804, 0, 0x00000000, 0x00000003 }, - { 0x1840, 0, 0x00000000, 0xffffffff }, - { 0x1844, 0, 0x00000000, 0xffffffff }, - { 0x1848, 0, 0x00000000, 0xffffffff }, - { 0x184c, 0, 0x00000000, 0xffffffff }, - { 0x1850, 0, 0x00000000, 0xffffffff }, - { 0x1900, 0, 0x7ffbffff, 0x00000000 }, - { 0x1904, 0, 0xffffffff, 0x00000000 }, - { 0x190c, 0, 0xffffffff, 0x00000000 }, - { 0x1914, 0, 0xffffffff, 0x00000000 }, - { 0x191c, 0, 0xffffffff, 0x00000000 }, - { 0x1924, 0, 0xffffffff, 0x00000000 }, - { 0x192c, 0, 0xffffffff, 0x00000000 }, - { 0x1934, 0, 0xffffffff, 0x00000000 }, - { 0x193c, 0, 0xffffffff, 0x00000000 }, - { 0x1944, 0, 0xffffffff, 0x00000000 }, - { 0x194c, 0, 0xffffffff, 0x00000000 }, - { 0x1954, 0, 0xffffffff, 0x00000000 }, - { 0x195c, 0, 0xffffffff, 0x00000000 }, - { 0x1964, 0, 0xffffffff, 0x00000000 }, - { 0x196c, 0, 0xffffffff, 0x00000000 }, - { 0x1974, 0, 0xffffffff, 0x00000000 }, - { 0x197c, 0, 0xffffffff, 0x00000000 }, - { 0x1980, 0, 0x0700ffff, 0x00000000 }, - - { 0x1c00, 0, 0x00000000, 0x00000001 }, - { 0x1c04, 0, 0x00000000, 0x00000003 }, - { 0x1c08, 0, 0x0000000f, 0x00000000 }, - { 0x1c40, 0, 0x00000000, 0xffffffff }, - { 0x1c44, 0, 0x00000000, 0xffffffff }, - { 0x1c48, 0, 0x00000000, 0xffffffff }, - { 0x1c4c, 0, 0x00000000, 0xffffffff }, - { 0x1c50, 0, 0x00000000, 0xffffffff }, - { 0x1d00, 0, 0x7ffbffff, 0x00000000 }, - { 0x1d04, 0, 0xffffffff, 0x00000000 }, - { 0x1d0c, 0, 0xffffffff, 0x00000000 }, - { 0x1d14, 0, 0xffffffff, 0x00000000 }, - { 0x1d1c, 0, 0xffffffff, 0x00000000 }, - { 0x1d24, 0, 0xffffffff, 0x00000000 }, - { 0x1d2c, 0, 0xffffffff, 0x00000000 }, - { 0x1d34, 0, 0xffffffff, 0x00000000 }, - { 0x1d3c, 0, 0xffffffff, 0x00000000 }, - { 0x1d44, 0, 0xffffffff, 0x00000000 }, - { 0x1d4c, 0, 0xffffffff, 0x00000000 }, - { 0x1d54, 0, 0xffffffff, 0x00000000 }, - { 0x1d5c, 0, 0xffffffff, 0x00000000 }, - { 0x1d64, 0, 0xffffffff, 0x00000000 }, - { 0x1d6c, 0, 0xffffffff, 0x00000000 }, - { 0x1d74, 0, 0xffffffff, 0x00000000 }, - { 0x1d7c, 0, 0xffffffff, 0x00000000 }, - { 0x1d80, 0, 0x0700ffff, 0x00000000 }, - - { 0x2004, 0, 0x00000000, 0x0337000f }, - { 0x2008, 0, 0xffffffff, 0x00000000 }, - { 0x200c, 0, 0xffffffff, 0x00000000 }, - { 0x2010, 0, 0xffffffff, 0x00000000 }, - { 0x2014, 0, 0x801fff80, 0x00000000 }, - { 0x2018, 0, 0x000003ff, 0x00000000 }, { 0x2800, 0, 0x00000000, 0x00000001 }, { 0x2804, 0, 0x00000000, 0x00003f01 }, @@ -3707,16 +3540,6 @@ bnx2_test_registers(struct bnx2 *bp) { 0x2c00, 0, 0x00000000, 0x00000011 }, { 0x2c04, 0, 0x00000000, 0x00030007 }, - { 0x3000, 0, 0x00000000, 0x00000001 }, - { 0x3004, 0, 0x00000000, 0x007007ff }, - { 0x3008, 0, 0x00000003, 0x00000000 }, - { 0x300c, 0, 0xffffffff, 0x00000000 }, - { 0x3010, 0, 0xffffffff, 0x00000000 }, - { 0x3014, 0, 0xffffffff, 0x00000000 }, - { 0x3034, 0, 0xffffffff, 0x00000000 }, - { 0x3038, 0, 0xffffffff, 0x00000000 }, - { 0x3050, 0, 0x00000001, 0x00000000 }, - { 0x3c00, 0, 0x00000000, 0x00000001 }, { 0x3c04, 0, 0x00000000, 0x00070000 }, { 0x3c08, 0, 0x00007f71, 0x07f00000 }, @@ -3726,88 +3549,11 @@ bnx2_test_registers(struct bnx2 *bp) { 0x3c18, 0, 0x00000000, 0xffffffff }, { 0x3c1c, 0, 0xfffff000, 0x00000000 }, { 0x3c20, 0, 0xffffff00, 0x00000000 }, - { 0x3c24, 0, 0xffffffff, 0x00000000 }, - { 0x3c28, 0, 0xffffffff, 0x00000000 }, - { 0x3c2c, 0, 0xffffffff, 0x00000000 }, - { 0x3c30, 0, 0xffffffff, 0x00000000 }, - { 0x3c34, 0, 0xffffffff, 0x00000000 }, - { 0x3c38, 0, 0xffffffff, 0x00000000 }, - { 0x3c3c, 0, 0xffffffff, 0x00000000 }, - { 0x3c40, 0, 0xffffffff, 0x00000000 }, - { 0x3c44, 0, 0xffffffff, 0x00000000 }, - { 0x3c48, 0, 0xffffffff, 0x00000000 }, - { 0x3c4c, 0, 0xffffffff, 0x00000000 }, - { 0x3c50, 0, 0xffffffff, 0x00000000 }, - { 0x3c54, 0, 0xffffffff, 0x00000000 }, - { 0x3c58, 0, 0xffffffff, 0x00000000 }, - { 0x3c5c, 0, 0xffffffff, 0x00000000 }, - { 0x3c60, 0, 0xffffffff, 0x00000000 }, - { 0x3c64, 0, 0xffffffff, 0x00000000 }, - { 0x3c68, 0, 0xffffffff, 0x00000000 }, - { 0x3c6c, 0, 0xffffffff, 0x00000000 }, - { 0x3c70, 0, 0xffffffff, 0x00000000 }, - { 0x3c74, 0, 0x0000003f, 0x00000000 }, - { 0x3c78, 0, 0x00000000, 0x00000000 }, - { 0x3c7c, 0, 0x00000000, 0x00000000 }, - { 0x3c80, 0, 0x3fffffff, 0x00000000 }, - { 0x3c84, 0, 0x0000003f, 0x00000000 }, - { 0x3c88, 0, 0x00000000, 0xffffffff }, - { 0x3c8c, 0, 0x00000000, 0xffffffff }, - - { 0x4000, 0, 0x00000000, 0x00000001 }, - { 0x4004, 0, 0x00000000, 0x00030000 }, - { 0x4008, 0, 0x00000ff0, 0x00000000 }, - { 0x400c, 0, 0xffffffff, 0x00000000 }, - { 0x4088, 0, 0x00000000, 0x00070303 }, - - { 0x4400, 0, 0x00000000, 0x00000001 }, - { 0x4404, 0, 0x00000000, 0x00003f01 }, - { 0x4408, 0, 0x7fff00ff, 0x00000000 }, - { 0x440c, 0, 0xffffffff, 0x00000000 }, - { 0x4410, 0, 0xffff, 0x0000 }, - { 0x4414, 0, 0xffff, 0x0000 }, - { 0x4418, 0, 0xffff, 0x0000 }, - { 0x441c, 0, 0xffff, 0x0000 }, - { 0x4428, 0, 0xffffffff, 0x00000000 }, - { 0x442c, 0, 0xffffffff, 0x00000000 }, - { 0x4430, 0, 0xffffffff, 0x00000000 }, - { 0x4434, 0, 0xffffffff, 0x00000000 }, - { 0x4438, 0, 0xffffffff, 0x00000000 }, - { 0x443c, 0, 0xffffffff, 0x00000000 }, - { 0x4440, 0, 0xffffffff, 0x00000000 }, - { 0x4444, 0, 0xffffffff, 0x00000000 }, - - { 0x4c00, 0, 0x00000000, 0x00000001 }, - { 0x4c04, 0, 0x00000000, 0x0000003f }, - { 0x4c08, 0, 0xffffffff, 0x00000000 }, - { 0x4c0c, 0, 0x0007fc00, 0x00000000 }, - { 0x4c10, 0, 0x80003fe0, 0x00000000 }, - { 0x4c14, 0, 0xffffffff, 0x00000000 }, - { 0x4c44, 0, 0x00000000, 0x9fff9fff }, - { 0x4c48, 0, 0x00000000, 0xb3009fff }, - { 0x4c4c, 0, 0x00000000, 0x77f33b30 }, - { 0x4c50, 0, 0x00000000, 0xffffffff }, { 0x5004, 0, 0x00000000, 0x0000007f }, { 0x5008, 0, 0x0f0007ff, 0x00000000 }, { 0x500c, 0, 0xf800f800, 0x07ff07ff }, - { 0x5400, 0, 0x00000008, 0x00000001 }, - { 0x5404, 0, 0x00000000, 0x0000003f }, - { 0x5408, 0, 0x0000001f, 0x00000000 }, - { 0x540c, 0, 0xffffffff, 0x00000000 }, - { 0x5410, 0, 0xffffffff, 0x00000000 }, - { 0x5414, 0, 0x0000ffff, 0x00000000 }, - { 0x5418, 0, 0x0000ffff, 0x00000000 }, - { 0x541c, 0, 0x0000ffff, 0x00000000 }, - { 0x5420, 0, 0x0000ffff, 0x00000000 }, - { 0x5428, 0, 0x000000ff, 0x00000000 }, - { 0x542c, 0, 0xff00ffff, 0x00000000 }, - { 0x5430, 0, 0x001fff80, 0x00000000 }, - { 0x5438, 0, 0xffffffff, 0x00000000 }, - { 0x543c, 0, 0xffffffff, 0x00000000 }, - { 0x5440, 0, 0xf800f800, 0x07ff07ff }, - { 0x5c00, 0, 0x00000000, 0x00000001 }, { 0x5c04, 0, 0x00000000, 0x0003000f }, { 0x5c08, 0, 0x00000003, 0x00000000 }, -- cgit v1.2.3 From 244ac4f446ac6a19caf5eb692c4844f29e6478bf Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 17:48:46 -0800 Subject: [BNX2]: Add ethtool -d support Add ETHTOOL_GREGS support. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 4be21b8501b..6fbb5486163 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -4540,6 +4540,64 @@ bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) info->fw_version[5] = 0; } +#define BNX2_REGDUMP_LEN (32 * 1024) + +static int +bnx2_get_regs_len(struct net_device *dev) +{ + return BNX2_REGDUMP_LEN; +} + +static void +bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) +{ + u32 *p = _p, i, offset; + u8 *orig_p = _p; + struct bnx2 *bp = netdev_priv(dev); + u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c, + 0x0800, 0x0880, 0x0c00, 0x0c10, + 0x0c30, 0x0d08, 0x1000, 0x101c, + 0x1040, 0x1048, 0x1080, 0x10a4, + 0x1400, 0x1490, 0x1498, 0x14f0, + 0x1500, 0x155c, 0x1580, 0x15dc, + 0x1600, 0x1658, 0x1680, 0x16d8, + 0x1800, 0x1820, 0x1840, 0x1854, + 0x1880, 0x1894, 0x1900, 0x1984, + 0x1c00, 0x1c0c, 0x1c40, 0x1c54, + 0x1c80, 0x1c94, 0x1d00, 0x1d84, + 0x2000, 0x2030, 0x23c0, 0x2400, + 0x2800, 0x2820, 0x2830, 0x2850, + 0x2b40, 0x2c10, 0x2fc0, 0x3058, + 0x3c00, 0x3c94, 0x4000, 0x4010, + 0x4080, 0x4090, 0x43c0, 0x4458, + 0x4c00, 0x4c18, 0x4c40, 0x4c54, + 0x4fc0, 0x5010, 0x53c0, 0x5444, + 0x5c00, 0x5c18, 0x5c80, 0x5c90, + 0x5fc0, 0x6000, 0x6400, 0x6428, + 0x6800, 0x6848, 0x684c, 0x6860, + 0x6888, 0x6910, 0x8000 }; + + regs->version = 0; + + memset(p, 0, BNX2_REGDUMP_LEN); + + if (!netif_running(bp->dev)) + return; + + i = 0; + offset = reg_boundaries[0]; + p += offset; + while (offset < BNX2_REGDUMP_LEN) { + *p++ = REG_RD(bp, offset); + offset += 4; + if (offset == reg_boundaries[i + 1]) { + offset = reg_boundaries[i + 2]; + p = (u32 *) (orig_p + offset); + i += 2; + } + } +} + static void bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { @@ -5106,6 +5164,8 @@ static struct ethtool_ops bnx2_ethtool_ops = { .get_settings = bnx2_get_settings, .set_settings = bnx2_set_settings, .get_drvinfo = bnx2_get_drvinfo, + .get_regs_len = bnx2_get_regs_len, + .get_regs = bnx2_get_regs, .get_wol = bnx2_get_wol, .set_wol = bnx2_set_wol, .nway_reset = bnx2_nway_reset, -- cgit v1.2.3 From 236b6394bb49ea58465c6f935a286d2342576f8d Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 17:49:02 -0800 Subject: [BNX2]: Fix bug when rx ring is full Fix the rx code path that does not handle the full rx ring correctly. When the rx ring is set to the max. size (i.e. 255), the consumer and producer indices will be the same when completing an rx packet. Fix the rx code to handle this condition properly. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 6fbb5486163..0d592f7c3a9 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -1656,23 +1656,30 @@ static inline void bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb, u16 cons, u16 prod) { - struct sw_bd *cons_rx_buf = &bp->rx_buf_ring[cons]; - struct sw_bd *prod_rx_buf = &bp->rx_buf_ring[prod]; - struct rx_bd *cons_bd = &bp->rx_desc_ring[cons]; - struct rx_bd *prod_bd = &bp->rx_desc_ring[prod]; + struct sw_bd *cons_rx_buf, *prod_rx_buf; + struct rx_bd *cons_bd, *prod_bd; + + cons_rx_buf = &bp->rx_buf_ring[cons]; + prod_rx_buf = &bp->rx_buf_ring[prod]; pci_dma_sync_single_for_device(bp->pdev, pci_unmap_addr(cons_rx_buf, mapping), bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); - prod_rx_buf->skb = cons_rx_buf->skb; - pci_unmap_addr_set(prod_rx_buf, mapping, - pci_unmap_addr(cons_rx_buf, mapping)); + bp->rx_prod_bseq += bp->rx_buf_use_size; - memcpy(prod_bd, cons_bd, 8); + prod_rx_buf->skb = skb; - bp->rx_prod_bseq += bp->rx_buf_use_size; + if (cons == prod) + return; + pci_unmap_addr_set(prod_rx_buf, mapping, + pci_unmap_addr(cons_rx_buf, mapping)); + + cons_bd = &bp->rx_desc_ring[cons]; + prod_bd = &bp->rx_desc_ring[prod]; + prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi; + prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo; } static int @@ -1699,14 +1706,19 @@ bnx2_rx_int(struct bnx2 *bp, int budget) u32 status; struct sw_bd *rx_buf; struct sk_buff *skb; + dma_addr_t dma_addr; sw_ring_cons = RX_RING_IDX(sw_cons); sw_ring_prod = RX_RING_IDX(sw_prod); rx_buf = &bp->rx_buf_ring[sw_ring_cons]; skb = rx_buf->skb; - pci_dma_sync_single_for_cpu(bp->pdev, - pci_unmap_addr(rx_buf, mapping), + + rx_buf->skb = NULL; + + dma_addr = pci_unmap_addr(rx_buf, mapping); + + pci_dma_sync_single_for_cpu(bp->pdev, dma_addr, bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE); rx_hdr = (struct l2_fhdr *) skb->data; @@ -1747,8 +1759,7 @@ bnx2_rx_int(struct bnx2 *bp, int budget) skb = new_skb; } else if (bnx2_alloc_rx_skb(bp, sw_ring_prod) == 0) { - pci_unmap_single(bp->pdev, - pci_unmap_addr(rx_buf, mapping), + pci_unmap_single(bp->pdev, dma_addr, bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); skb_reserve(skb, bp->rx_offset); @@ -1794,8 +1805,6 @@ reuse_rx: rx_pkt++; next_rx: - rx_buf->skb = NULL; - sw_cons = NEXT_RX_BD(sw_cons); sw_prod = NEXT_RX_BD(sw_prod); @@ -3360,7 +3369,7 @@ bnx2_init_rx_ring(struct bnx2 *bp) val = (u64) bp->rx_desc_mapping & 0xffffffff; CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val); - for ( ;ring_prod < bp->rx_ring_size; ) { + for (i = 0; i < bp->rx_ring_size; i++) { if (bnx2_alloc_rx_skb(bp, ring_prod) < 0) { break; } -- cgit v1.2.3 From 13daffa2f2ba65674e7816a0e95e7b93246cb686 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 17:49:20 -0800 Subject: [BNX2]: Support larger rx ring sizes (part 1) Increase maximum receive ring size from 255 to 1020 by supporting up to 4 linked pages of receive descriptors. To accomodate the higher memory usage, each physical descriptor page is allocated separately and the software ring that keeps track of the SKBs and the DMA addresses is allocated using vmalloc. Some of the receive-related fields in the bp structure are re- organized a bit for better locality of reference. The max. was reduced to 1020 from 4080 after discussion with David Miller. This patch contains ring init code changes only. This next patch contains rx data path code changes. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 117 ++++++++++++++++++++++++++++++++++++++--------------- drivers/net/bnx2.h | 36 ++++++++++------- 2 files changed, 107 insertions(+), 46 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 0d592f7c3a9..03c47cf04e9 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -360,6 +360,8 @@ bnx2_netif_start(struct bnx2 *bp) static void bnx2_free_mem(struct bnx2 *bp) { + int i; + if (bp->stats_blk) { pci_free_consistent(bp->pdev, sizeof(struct statistics_block), bp->stats_blk, bp->stats_blk_mapping); @@ -378,19 +380,23 @@ bnx2_free_mem(struct bnx2 *bp) } kfree(bp->tx_buf_ring); bp->tx_buf_ring = NULL; - if (bp->rx_desc_ring) { - pci_free_consistent(bp->pdev, - sizeof(struct rx_bd) * RX_DESC_CNT, - bp->rx_desc_ring, bp->rx_desc_mapping); - bp->rx_desc_ring = NULL; - } - kfree(bp->rx_buf_ring); + for (i = 0; i < bp->rx_max_ring; i++) { + if (bp->rx_desc_ring[i]) + pci_free_consistent(bp->pdev, + sizeof(struct rx_bd) * RX_DESC_CNT, + bp->rx_desc_ring[i], + bp->rx_desc_mapping[i]); + bp->rx_desc_ring[i] = NULL; + } + vfree(bp->rx_buf_ring); bp->rx_buf_ring = NULL; } static int bnx2_alloc_mem(struct bnx2 *bp) { + int i; + bp->tx_buf_ring = kmalloc(sizeof(struct sw_bd) * TX_DESC_CNT, GFP_KERNEL); if (bp->tx_buf_ring == NULL) @@ -404,18 +410,23 @@ bnx2_alloc_mem(struct bnx2 *bp) if (bp->tx_desc_ring == NULL) goto alloc_mem_err; - bp->rx_buf_ring = kmalloc(sizeof(struct sw_bd) * RX_DESC_CNT, - GFP_KERNEL); + bp->rx_buf_ring = vmalloc(sizeof(struct sw_bd) * RX_DESC_CNT * + bp->rx_max_ring); if (bp->rx_buf_ring == NULL) goto alloc_mem_err; - memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT); - bp->rx_desc_ring = pci_alloc_consistent(bp->pdev, - sizeof(struct rx_bd) * - RX_DESC_CNT, - &bp->rx_desc_mapping); - if (bp->rx_desc_ring == NULL) - goto alloc_mem_err; + memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT * + bp->rx_max_ring); + + for (i = 0; i < bp->rx_max_ring; i++) { + bp->rx_desc_ring[i] = + pci_alloc_consistent(bp->pdev, + sizeof(struct rx_bd) * RX_DESC_CNT, + &bp->rx_desc_mapping[i]); + if (bp->rx_desc_ring[i] == NULL) + goto alloc_mem_err; + + } bp->status_blk = pci_alloc_consistent(bp->pdev, sizeof(struct status_block), @@ -1520,7 +1531,7 @@ bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index) struct sk_buff *skb; struct sw_bd *rx_buf = &bp->rx_buf_ring[index]; dma_addr_t mapping; - struct rx_bd *rxbd = &bp->rx_desc_ring[index]; + struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)]; unsigned long align; skb = dev_alloc_skb(bp->rx_buf_size); @@ -3349,24 +3360,32 @@ bnx2_init_rx_ring(struct bnx2 *bp) bp->hw_rx_cons = 0; bp->rx_prod_bseq = 0; - rxbd = &bp->rx_desc_ring[0]; - for (i = 0; i < MAX_RX_DESC_CNT; i++, rxbd++) { - rxbd->rx_bd_len = bp->rx_buf_use_size; - rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END; - } + for (i = 0; i < bp->rx_max_ring; i++) { + int j; - rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping >> 32; - rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping & 0xffffffff; + rxbd = &bp->rx_desc_ring[i][0]; + for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) { + rxbd->rx_bd_len = bp->rx_buf_use_size; + rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END; + } + if (i == (bp->rx_max_ring - 1)) + j = 0; + else + j = i + 1; + rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping[j] >> 32; + rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping[j] & + 0xffffffff; + } val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE; val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2; val |= 0x02 << 8; CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_CTX_TYPE, val); - val = (u64) bp->rx_desc_mapping >> 32; + val = (u64) bp->rx_desc_mapping[0] >> 32; CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_HI, val); - val = (u64) bp->rx_desc_mapping & 0xffffffff; + val = (u64) bp->rx_desc_mapping[0] & 0xffffffff; CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val); for (i = 0; i < bp->rx_ring_size; i++) { @@ -3383,6 +3402,29 @@ bnx2_init_rx_ring(struct bnx2 *bp) REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq); } +static void +bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size) +{ + u32 num_rings, max; + + bp->rx_ring_size = size; + num_rings = 1; + while (size > MAX_RX_DESC_CNT) { + size -= MAX_RX_DESC_CNT; + num_rings++; + } + /* round to next power of 2 */ + max = MAX_RX_RINGS; + while ((max & num_rings) == 0) + max >>= 1; + + if (num_rings != max) + max <<= 1; + + bp->rx_max_ring = max; + bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1; +} + static void bnx2_free_tx_skbs(struct bnx2 *bp) { @@ -3428,7 +3470,7 @@ bnx2_free_rx_skbs(struct bnx2 *bp) if (bp->rx_buf_ring == NULL) return; - for (i = 0; i < RX_DESC_CNT; i++) { + for (i = 0; i < bp->rx_max_ring_idx; i++) { struct sw_bd *rx_buf = &bp->rx_buf_ring[i]; struct sk_buff *skb = rx_buf->skb; @@ -4792,7 +4834,7 @@ bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { struct bnx2 *bp = netdev_priv(dev); - ering->rx_max_pending = MAX_RX_DESC_CNT; + ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT; ering->rx_mini_max_pending = 0; ering->rx_jumbo_max_pending = 0; @@ -4809,17 +4851,28 @@ bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) { struct bnx2 *bp = netdev_priv(dev); - if ((ering->rx_pending > MAX_RX_DESC_CNT) || + if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) || (ering->tx_pending > MAX_TX_DESC_CNT) || (ering->tx_pending <= MAX_SKB_FRAGS)) { return -EINVAL; } - bp->rx_ring_size = ering->rx_pending; + if (netif_running(bp->dev)) { + bnx2_netif_stop(bp); + bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET); + bnx2_free_skbs(bp); + bnx2_free_mem(bp); + } + + bnx2_set_rx_ring_size(bp, ering->rx_pending); bp->tx_ring_size = ering->tx_pending; if (netif_running(bp->dev)) { - bnx2_netif_stop(bp); + int rc; + + rc = bnx2_alloc_mem(bp); + if (rc) + return rc; bnx2_init_nic(bp); bnx2_netif_start(bp); } @@ -5493,7 +5546,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) bp->mac_addr[5] = (u8) reg; bp->tx_ring_size = MAX_TX_DESC_CNT; - bp->rx_ring_size = 100; + bnx2_set_rx_ring_size(bp, 100); bp->rx_csum = 1; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 9f691cbd666..beb2e8bcc65 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -3792,8 +3792,10 @@ struct l2_fhdr { #define TX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct tx_bd)) #define MAX_TX_DESC_CNT (TX_DESC_CNT - 1) +#define MAX_RX_RINGS 4 #define RX_DESC_CNT (BCM_PAGE_SIZE / sizeof(struct rx_bd)) #define MAX_RX_DESC_CNT (RX_DESC_CNT - 1) +#define MAX_TOTAL_RX_DESC_CNT (MAX_RX_DESC_CNT * MAX_RX_RINGS) #define NEXT_TX_BD(x) (((x) & (MAX_TX_DESC_CNT - 1)) == \ (MAX_TX_DESC_CNT - 1)) ? \ @@ -3805,8 +3807,10 @@ struct l2_fhdr { (MAX_RX_DESC_CNT - 1)) ? \ (x) + 2 : (x) + 1 -#define RX_RING_IDX(x) ((x) & MAX_RX_DESC_CNT) +#define RX_RING_IDX(x) ((x) & bp->rx_max_ring_idx) +#define RX_RING(x) (((x) & ~MAX_RX_DESC_CNT) >> 8) +#define RX_IDX(x) ((x) & MAX_RX_DESC_CNT) /* Context size. */ #define CTX_SHIFT 7 @@ -3903,6 +3907,15 @@ struct bnx2 { struct status_block *status_blk; u32 last_status_idx; + u32 flags; +#define PCIX_FLAG 1 +#define PCI_32BIT_FLAG 2 +#define ONE_TDMA_FLAG 4 /* no longer used */ +#define NO_WOL_FLAG 8 +#define USING_DAC_FLAG 0x10 +#define USING_MSI_FLAG 0x20 +#define ASF_ENABLE_FLAG 0x40 + struct tx_bd *tx_desc_ring; struct sw_bd *tx_buf_ring; u32 tx_prod_bseq; @@ -3920,19 +3933,22 @@ struct bnx2 { u32 rx_offset; u32 rx_buf_use_size; /* useable size */ u32 rx_buf_size; /* with alignment */ - struct rx_bd *rx_desc_ring; - struct sw_bd *rx_buf_ring; + u32 rx_max_ring_idx; + u32 rx_prod_bseq; u16 rx_prod; u16 rx_cons; u32 rx_csum; + struct sw_bd *rx_buf_ring; + struct rx_bd *rx_desc_ring[MAX_RX_RINGS]; + /* Only used to synchronize netif_stop_queue/wake_queue when tx */ /* ring is full */ spinlock_t tx_lock; - /* End of fileds used in the performance code paths. */ + /* End of fields used in the performance code paths. */ char *name; @@ -3945,15 +3961,6 @@ struct bnx2 { /* Used to synchronize phy accesses. */ spinlock_t phy_lock; - u32 flags; -#define PCIX_FLAG 1 -#define PCI_32BIT_FLAG 2 -#define ONE_TDMA_FLAG 4 /* no longer used */ -#define NO_WOL_FLAG 8 -#define USING_DAC_FLAG 0x10 -#define USING_MSI_FLAG 0x20 -#define ASF_ENABLE_FLAG 0x40 - u32 phy_flags; #define PHY_SERDES_FLAG 1 #define PHY_CRC_FIX_FLAG 2 @@ -4004,8 +4011,9 @@ struct bnx2 { dma_addr_t tx_desc_mapping; + int rx_max_ring; int rx_ring_size; - dma_addr_t rx_desc_mapping; + dma_addr_t rx_desc_mapping[MAX_RX_RINGS]; u16 tx_quick_cons_trip; u16 tx_quick_cons_trip_int; -- cgit v1.2.3 From 3fdfcc2c95ffc7ee04b480a4c1fd4809b5ff2f7c Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 17:49:49 -0800 Subject: [BNX2]: Support larger rx ring sizes (part 2) Support bigger rx ring sizes (up to 1020) in the rx fast path. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 03c47cf04e9..b36515e9537 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -1687,8 +1687,8 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb, pci_unmap_addr_set(prod_rx_buf, mapping, pci_unmap_addr(cons_rx_buf, mapping)); - cons_bd = &bp->rx_desc_ring[cons]; - prod_bd = &bp->rx_desc_ring[prod]; + cons_bd = &bp->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)]; + prod_bd = &bp->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)]; prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi; prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo; } -- cgit v1.2.3 From 1d60290f27e7dc4bce2c43922d0bfa9abd246fc9 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 17:50:08 -0800 Subject: [BNX2]: Update version Update version to 1.4.37. Add missing flush_scheduled_work() in bnx2_suspend as noted by Jeff Garzik. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index b36515e9537..1f4b788245f 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -14,8 +14,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.4.31" -#define DRV_MODULE_RELDATE "January 19, 2006" +#define DRV_MODULE_VERSION "1.4.37" +#define DRV_MODULE_RELDATE "February 1, 2006" #define RUN_AT(x) (jiffies + (x)) @@ -5765,6 +5765,7 @@ bnx2_suspend(struct pci_dev *pdev, pm_message_t state) if (!netif_running(dev)) return 0; + flush_scheduled_work(); bnx2_netif_stop(bp); netif_device_detach(dev); del_timer_sync(&bp->timer); -- cgit v1.2.3 From 0d36f37bb1e1cbadca6dc90a840bb2bc9ab51c44 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 17:55:25 -0800 Subject: [BNX2]: include Include so that it compiles properly on all archs. Update version to 1.4.38. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 4 ++-- drivers/net/bnx2.h | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 1f4b788245f..7d213707008 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -14,8 +14,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.4.37" -#define DRV_MODULE_RELDATE "February 1, 2006" +#define DRV_MODULE_VERSION "1.4.38" +#define DRV_MODULE_RELDATE "February 10, 2006" #define RUN_AT(x) (jiffies + (x)) diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index beb2e8bcc65..fd4b7f2eb47 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From ec4f32d550b94b4b66c9c7689bc09c6b32c8e82e Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 20 Mar 2006 18:54:03 -0800 Subject: [IRDA]: nsc-ircc: ISAPnP support This enables PnP support for the nsc-ircc chipset. Since we can't fetch the chipset cfg_base from the PnP layer, we just use the PnP information as one more hint when probing the chip. Signed-off-by: Jean Tourrilhes Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/nsc-ircc.c | 185 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 151 insertions(+), 34 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index ee717d0e939..282414ba22f 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -12,6 +12,7 @@ * Copyright (c) 1998-2000 Dag Brattli * Copyright (c) 1998 Lichen Wang, * Copyright (c) 1998 Actisys Corp., www.actisys.com + * Copyright (c) 2000-2004 Jean Tourrilhes * All Rights Reserved * * This program is free software; you can redistribute it and/or @@ -53,6 +54,7 @@ #include #include #include +#include #include #include @@ -78,8 +80,8 @@ static int dongle_id; /* Use BIOS settions by default, but user may supply module parameters */ static unsigned int io[] = { ~0, ~0, ~0, ~0 }; -static unsigned int irq[] = { 0, 0, 0, 0, 0 }; -static unsigned int dma[] = { 0, 0, 0, 0, 0 }; +static unsigned int irq[] = { 0, 0, 0, 0 }; +static unsigned int dma[] = { 0, 0, 0, 0 }; static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info); static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info); @@ -87,6 +89,7 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info); static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info); static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info); static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info); +static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id); /* These are the known NSC chips */ static nsc_chip_t chips[] = { @@ -104,7 +107,6 @@ static nsc_chip_t chips[] = { { NULL } }; -/* Max 4 instances for now */ static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL }; static char *dongle_types[] = { @@ -126,8 +128,24 @@ static char *dongle_types[] = { "No dongle connected", }; +/* PNP probing */ +static chipio_t pnp_info; +static const struct pnp_device_id nsc_ircc_pnp_table[] = { + { .id = "NSC6001", .driver_data = 0 }, + { .id = "IBM0071", .driver_data = 0 }, + { } +}; + +MODULE_DEVICE_TABLE(pnp, nsc_ircc_pnp_table); + +static struct pnp_driver nsc_ircc_pnp_driver = { + .name = "nsc-ircc", + .id_table = nsc_ircc_pnp_table, + .probe = nsc_ircc_pnp_probe, +}; + /* Some prototypes */ -static int nsc_ircc_open(int i, chipio_t *info); +static int nsc_ircc_open(chipio_t *info); static int nsc_ircc_close(struct nsc_ircc_cb *self); static int nsc_ircc_setup(chipio_t *info); static void nsc_ircc_pio_receive(struct nsc_ircc_cb *self); @@ -148,6 +166,10 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev); static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data); +/* Globals */ +static int pnp_registered; +static int pnp_succeeded; + /* * Function nsc_ircc_init () * @@ -158,28 +180,30 @@ static int __init nsc_ircc_init(void) { chipio_t info; nsc_chip_t *chip; - int ret = -ENODEV; + int ret; int cfg_base; int cfg, id; int reg; int i = 0; + /* Register with PnP subsystem to detect disable ports */ + ret = pnp_register_driver(&nsc_ircc_pnp_driver); + + if (ret >= 0) + pnp_registered = 1; + + ret = -ENODEV; + /* Probe for all the NSC chipsets we know about */ - for (chip=chips; chip->name ; chip++) { + for (chip = chips; chip->name ; chip++) { IRDA_DEBUG(2, "%s(), Probing for %s ...\n", __FUNCTION__, chip->name); /* Try all config registers for this chip */ - for (cfg=0; cfg<3; cfg++) { + for (cfg = 0; cfg < ARRAY_SIZE(chip->cfg); cfg++) { cfg_base = chip->cfg[cfg]; if (!cfg_base) continue; - - memset(&info, 0, sizeof(chipio_t)); - info.cfg_base = cfg_base; - info.fir_base = io[i]; - info.dma = dma[i]; - info.irq = irq[i]; /* Read index register */ reg = inb(cfg_base); @@ -194,24 +218,64 @@ static int __init nsc_ircc_init(void) if ((id & chip->cid_mask) == chip->cid_value) { IRDA_DEBUG(2, "%s() Found %s chip, revision=%d\n", __FUNCTION__, chip->name, id & ~chip->cid_mask); - /* - * If the user supplies the base address, then - * we init the chip, if not we probe the values - * set by the BIOS - */ - if (io[i] < 0x2000) { - chip->init(chip, &info); - } else - chip->probe(chip, &info); - if (nsc_ircc_open(i, &info) == 0) - ret = 0; + /* + * If we found a correct PnP setting, + * we first try it. + */ + if (pnp_succeeded) { + memset(&info, 0, sizeof(chipio_t)); + info.cfg_base = cfg_base; + info.fir_base = pnp_info.fir_base; + info.dma = pnp_info.dma; + info.irq = pnp_info.irq; + + if (info.fir_base < 0x2000) { + IRDA_MESSAGE("%s, chip->init\n", driver_name); + chip->init(chip, &info); + } else + chip->probe(chip, &info); + + if (nsc_ircc_open(&info) >= 0) + ret = 0; + } + + /* + * Opening based on PnP values failed. + * Let's fallback to user values, or probe + * the chip. + */ + if (ret) { + IRDA_DEBUG(2, "%s, PnP init failed\n", driver_name); + memset(&info, 0, sizeof(chipio_t)); + info.cfg_base = cfg_base; + info.fir_base = io[i]; + info.dma = dma[i]; + info.irq = irq[i]; + + /* + * If the user supplies the base address, then + * we init the chip, if not we probe the values + * set by the BIOS + */ + if (io[i] < 0x2000) { + chip->init(chip, &info); + } else + chip->probe(chip, &info); + + if (nsc_ircc_open(&info) >= 0) + ret = 0; + } i++; } else { IRDA_DEBUG(2, "%s(), Wrong chip id=0x%02x\n", __FUNCTION__, id); } } - + } + + if (ret) { + pnp_unregister_driver(&nsc_ircc_pnp_driver); + pnp_registered = 0; } return ret; @@ -229,10 +293,15 @@ static void __exit nsc_ircc_cleanup(void) pm_unregister_all(nsc_ircc_pmproc); - for (i=0; i < 4; i++) { + for (i = 0; i < ARRAY_SIZE(dev_self); i++) { if (dev_self[i]) nsc_ircc_close(dev_self[i]); } + + if (pnp_registered) + pnp_unregister_driver(&nsc_ircc_pnp_driver); + + pnp_registered = 0; } /* @@ -241,16 +310,27 @@ static void __exit nsc_ircc_cleanup(void) * Open driver instance * */ -static int __init nsc_ircc_open(int i, chipio_t *info) +static int __init nsc_ircc_open(chipio_t *info) { struct net_device *dev; struct nsc_ircc_cb *self; - struct pm_dev *pmdev; + struct pm_dev *pmdev; void *ret; - int err; + int err, chip_index; IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + + for (chip_index = 0; chip_index < ARRAY_SIZE(dev_self); chip_index++) { + if (!dev_self[chip_index]) + break; + } + + if (chip_index == ARRAY_SIZE(dev_self)) { + IRDA_ERROR("%s(), maximum number of supported chips reached!\n", __FUNCTION__); + return -ENOMEM; + } + IRDA_MESSAGE("%s, Found chip at base=0x%03x\n", driver_name, info->cfg_base); @@ -271,8 +351,8 @@ static int __init nsc_ircc_open(int i, chipio_t *info) spin_lock_init(&self->lock); /* Need to store self somewhere */ - dev_self[i] = self; - self->index = i; + dev_self[chip_index] = self; + self->index = chip_index; /* Initialize IO */ self->io.cfg_base = info->cfg_base; @@ -351,7 +431,7 @@ static int __init nsc_ircc_open(int i, chipio_t *info) /* Check if user has supplied a valid dongle id or not */ if ((dongle_id <= 0) || - (dongle_id >= (sizeof(dongle_types) / sizeof(dongle_types[0]))) ) { + (dongle_id >= ARRAY_SIZE(dongle_types))) { dongle_id = nsc_ircc_read_dongle_id(self->io.fir_base); IRDA_MESSAGE("%s, Found dongle: %s\n", driver_name, @@ -368,7 +448,7 @@ static int __init nsc_ircc_open(int i, chipio_t *info) if (pmdev) pmdev->data = self; - return 0; + return chip_index; out4: dma_free_coherent(NULL, self->tx_buff.truesize, self->tx_buff.head, self->tx_buff_dma); @@ -379,7 +459,7 @@ static int __init nsc_ircc_open(int i, chipio_t *info) release_region(self->io.fir_base, self->io.fir_ext); out1: free_netdev(dev); - dev_self[i] = NULL; + dev_self[chip_index] = NULL; return err; } @@ -806,6 +886,43 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info) return 0; } +/* PNP probing */ +static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id) +{ + memset(&pnp_info, 0, sizeof(chipio_t)); + pnp_info.irq = -1; + pnp_info.dma = -1; + pnp_succeeded = 1; + + /* There don't seem to be any way to get the cfg_base. + * On my box, cfg_base is in the PnP descriptor of the + * motherboard. Oh well... Jean II */ + + if (pnp_port_valid(dev, 0) && + !(pnp_port_flags(dev, 0) & IORESOURCE_DISABLED)) + pnp_info.fir_base = pnp_port_start(dev, 0); + + if (pnp_irq_valid(dev, 0) && + !(pnp_irq_flags(dev, 0) & IORESOURCE_DISABLED)) + pnp_info.irq = pnp_irq(dev, 0); + + if (pnp_dma_valid(dev, 0) && + !(pnp_dma_flags(dev, 0) & IORESOURCE_DISABLED)) + pnp_info.dma = pnp_dma(dev, 0); + + IRDA_DEBUG(0, "%s() : From PnP, found firbase 0x%03X ; irq %d ; dma %d.\n", + __FUNCTION__, pnp_info.fir_base, pnp_info.irq, pnp_info.dma); + + if((pnp_info.fir_base == 0) || + (pnp_info.irq == -1) || (pnp_info.dma == -1)) { + /* Returning an error will disable the device. Yuck ! */ + //return -EINVAL; + pnp_succeeded = 0; + } + + return 0; +} + /* * Function nsc_ircc_setup (info) * -- cgit v1.2.3 From 3b99b93baba4cbf4fd3d206e65e81a070b21b560 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Mar 2006 18:59:05 -0800 Subject: [IRDA]: nsc-ircc: PM update This patch brings the nsc-ircc code to a more up to date power management scheme, following the current device model. Signed-off-by: Dmitry Torokhov Signed-off-by: Rudolf Marek Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/nsc-ircc.c | 131 ++++++++++++++++++++++++++++++++------------ drivers/net/irda/nsc-ircc.h | 2 +- 2 files changed, 98 insertions(+), 35 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 282414ba22f..81a4ccf54c5 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -55,14 +55,12 @@ #include #include #include +#include #include #include #include -#include -#include - #include #include #include @@ -74,6 +72,19 @@ static char *driver_name = "nsc-ircc"; +/* Power Management */ +#define NSC_IRCC_DRIVER_NAME "nsc-ircc" +static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state); +static int nsc_ircc_resume(struct platform_device *dev); + +static struct platform_driver nsc_ircc_driver = { + .suspend = nsc_ircc_suspend, + .resume = nsc_ircc_resume, + .driver = { + .name = NSC_IRCC_DRIVER_NAME, + }, +}; + /* Module parameters */ static int qos_mtt_bits = 0x07; /* 1 ms or more */ static int dongle_id; @@ -164,7 +175,6 @@ static int nsc_ircc_net_open(struct net_device *dev); static int nsc_ircc_net_close(struct net_device *dev); static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev); -static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data); /* Globals */ static int pnp_registered; @@ -186,6 +196,12 @@ static int __init nsc_ircc_init(void) int reg; int i = 0; + ret = platform_driver_register(&nsc_ircc_driver); + if (ret) { + IRDA_ERROR("%s, Can't register driver!\n", driver_name); + return ret; + } + /* Register with PnP subsystem to detect disable ports */ ret = pnp_register_driver(&nsc_ircc_pnp_driver); @@ -274,6 +290,7 @@ static int __init nsc_ircc_init(void) } if (ret) { + platform_driver_unregister(&nsc_ircc_driver); pnp_unregister_driver(&nsc_ircc_pnp_driver); pnp_registered = 0; } @@ -291,13 +308,13 @@ static void __exit nsc_ircc_cleanup(void) { int i; - pm_unregister_all(nsc_ircc_pmproc); - for (i = 0; i < ARRAY_SIZE(dev_self); i++) { if (dev_self[i]) nsc_ircc_close(dev_self[i]); } + platform_driver_unregister(&nsc_ircc_driver); + if (pnp_registered) pnp_unregister_driver(&nsc_ircc_pnp_driver); @@ -314,7 +331,6 @@ static int __init nsc_ircc_open(chipio_t *info) { struct net_device *dev; struct nsc_ircc_cb *self; - struct pm_dev *pmdev; void *ret; int err, chip_index; @@ -444,11 +460,18 @@ static int __init nsc_ircc_open(chipio_t *info) self->io.dongle_id = dongle_id; nsc_ircc_init_dongle_interface(self->io.fir_base, dongle_id); - pmdev = pm_register(PM_SYS_DEV, PM_SYS_IRDA, nsc_ircc_pmproc); - if (pmdev) - pmdev->data = self; + self->pldev = platform_device_register_simple(NSC_IRCC_DRIVER_NAME, + self->index, NULL, 0); + if (IS_ERR(self->pldev)) { + err = PTR_ERR(self->pldev); + goto out5; + } + platform_set_drvdata(self->pldev, self); return chip_index; + + out5: + unregister_netdev(dev); out4: dma_free_coherent(NULL, self->tx_buff.truesize, self->tx_buff.head, self->tx_buff_dma); @@ -479,6 +502,8 @@ static int __exit nsc_ircc_close(struct nsc_ircc_cb *self) iobase = self->io.fir_base; + platform_device_unregister(self->pldev); + /* Remove netdevice */ unregister_netdev(self->netdev); @@ -2278,45 +2303,83 @@ static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev) return &self->stats; } -static void nsc_ircc_suspend(struct nsc_ircc_cb *self) +static int nsc_ircc_suspend(struct platform_device *dev, pm_message_t state) { - IRDA_MESSAGE("%s, Suspending\n", driver_name); + struct nsc_ircc_cb *self = platform_get_drvdata(dev); + int bank; + unsigned long flags; + int iobase = self->io.fir_base; if (self->io.suspended) - return; + return 0; - nsc_ircc_net_close(self->netdev); + IRDA_DEBUG(1, "%s, Suspending\n", driver_name); + rtnl_lock(); + if (netif_running(self->netdev)) { + netif_device_detach(self->netdev); + spin_lock_irqsave(&self->lock, flags); + /* Save current bank */ + bank = inb(iobase+BSR); + + /* Disable interrupts */ + switch_bank(iobase, BANK0); + outb(0, iobase+IER); + + /* Restore bank register */ + outb(bank, iobase+BSR); + + spin_unlock_irqrestore(&self->lock, flags); + free_irq(self->io.irq, self->netdev); + disable_dma(self->io.dma); + } self->io.suspended = 1; + rtnl_unlock(); + + return 0; } -static void nsc_ircc_wakeup(struct nsc_ircc_cb *self) +static int nsc_ircc_resume(struct platform_device *dev) { + struct nsc_ircc_cb *self = platform_get_drvdata(dev); + unsigned long flags; + if (!self->io.suspended) - return; + return 0; + IRDA_DEBUG(1, "%s, Waking up\n", driver_name); + + rtnl_lock(); nsc_ircc_setup(&self->io); - nsc_ircc_net_open(self->netdev); - - IRDA_MESSAGE("%s, Waking up\n", driver_name); + nsc_ircc_init_dongle_interface(self->io.fir_base, self->io.dongle_id); + if (netif_running(self->netdev)) { + if (request_irq(self->io.irq, nsc_ircc_interrupt, 0, + self->netdev->name, self->netdev)) { + IRDA_WARNING("%s, unable to allocate irq=%d\n", + driver_name, self->io.irq); + + /* + * Don't fail resume process, just kill this + * network interface + */ + unregister_netdevice(self->netdev); + } else { + spin_lock_irqsave(&self->lock, flags); + nsc_ircc_change_speed(self, self->io.speed); + spin_unlock_irqrestore(&self->lock, flags); + netif_device_attach(self->netdev); + } + + } else { + spin_lock_irqsave(&self->lock, flags); + nsc_ircc_change_speed(self, 9600); + spin_unlock_irqrestore(&self->lock, flags); + } self->io.suspended = 0; -} + rtnl_unlock(); -static int nsc_ircc_pmproc(struct pm_dev *dev, pm_request_t rqst, void *data) -{ - struct nsc_ircc_cb *self = (struct nsc_ircc_cb*) dev->data; - if (self) { - switch (rqst) { - case PM_SUSPEND: - nsc_ircc_suspend(self); - break; - case PM_RESUME: - nsc_ircc_wakeup(self); - break; - } - } - return 0; + return 0; } MODULE_AUTHOR("Dag Brattli "); diff --git a/drivers/net/irda/nsc-ircc.h b/drivers/net/irda/nsc-ircc.h index 6edf7e51462..dacf671abcd 100644 --- a/drivers/net/irda/nsc-ircc.h +++ b/drivers/net/irda/nsc-ircc.h @@ -269,7 +269,7 @@ struct nsc_ircc_cb { __u32 new_speed; int index; /* Instance index */ - struct pm_dev *dev; + struct platform_device *pldev; }; static inline void switch_bank(int iobase, int bank) -- cgit v1.2.3 From 0ed79c9b7dea5cd9a55589a495cf96f00cd037d9 Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Mon, 20 Mar 2006 18:59:40 -0800 Subject: [IRDA]: nsc-ircc: support for yet another Thinkpad IrDA chipset This patch simply adds support for a variation of the nsc-ircc PC8739x chipset, found in some IBM Thinkpad laptops. Signed-off-by: Jean Tourrilhes Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/nsc-ircc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 81a4ccf54c5..83141a3ff54 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -90,9 +90,9 @@ static int qos_mtt_bits = 0x07; /* 1 ms or more */ static int dongle_id; /* Use BIOS settions by default, but user may supply module parameters */ -static unsigned int io[] = { ~0, ~0, ~0, ~0 }; -static unsigned int irq[] = { 0, 0, 0, 0 }; -static unsigned int dma[] = { 0, 0, 0, 0 }; +static unsigned int io[] = { ~0, ~0, ~0, ~0, ~0 }; +static unsigned int irq[] = { 0, 0, 0, 0, 0 }; +static unsigned int dma[] = { 0, 0, 0, 0, 0 }; static int nsc_ircc_probe_108(nsc_chip_t *chip, chipio_t *info); static int nsc_ircc_probe_338(nsc_chip_t *chip, chipio_t *info); @@ -115,10 +115,12 @@ static nsc_chip_t chips[] = { /* Contributed by Jan Frey - IBM A30/A31 */ { "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff, nsc_ircc_probe_39x, nsc_ircc_init_39x }, + { "IBM", { 0x2e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff, + nsc_ircc_probe_39x, nsc_ircc_init_39x }, { NULL } }; -static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL }; +static struct nsc_ircc_cb *dev_self[] = { NULL, NULL, NULL, NULL, NULL }; static char *dongle_types[] = { "Differential serial interface", -- cgit v1.2.3 From 034888262eb8de1a91bc471d4e6d8173f6b3dbda Mon Sep 17 00:00:00 2001 From: David chosrova Date: Mon, 20 Mar 2006 19:00:04 -0800 Subject: [IRDA]: sti/cli removal from EP7211 IrDA driver This patch replaces the deprecated sti/cli routines with the corresponding spin_lock ones. Signed-off-by: David chosrova Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/ep7211_ir.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/ep7211_ir.c b/drivers/net/irda/ep7211_ir.c index 31896262d21..4cba38f7e4a 100644 --- a/drivers/net/irda/ep7211_ir.c +++ b/drivers/net/irda/ep7211_ir.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -23,6 +24,8 @@ static void ep7211_ir_close(dongle_t *self); static int ep7211_ir_change_speed(struct irda_task *task); static int ep7211_ir_reset(struct irda_task *task); +static DEFINE_SPINLOCK(ep7211_lock); + static struct dongle_reg dongle = { .type = IRDA_EP7211_IR, .open = ep7211_ir_open, @@ -36,7 +39,7 @@ static void ep7211_ir_open(dongle_t *self, struct qos_info *qos) { unsigned int syscon1, flags; - save_flags(flags); cli(); + spin_lock_irqsave(&ep7211_lock, flags); /* Turn on the SIR encoder. */ syscon1 = clps_readl(SYSCON1); @@ -46,14 +49,14 @@ static void ep7211_ir_open(dongle_t *self, struct qos_info *qos) /* XXX: We should disable modem status interrupts on the first UART (interrupt #14). */ - restore_flags(flags); + spin_unlock_irqrestore(&ep7211_lock, flags); } static void ep7211_ir_close(dongle_t *self) { unsigned int syscon1, flags; - save_flags(flags); cli(); + spin_lock_irqsave(&ep7211_lock, flags); /* Turn off the SIR encoder. */ syscon1 = clps_readl(SYSCON1); @@ -63,7 +66,7 @@ static void ep7211_ir_close(dongle_t *self) /* XXX: If we've disabled the modem status interrupts, we should reset them back to their original state. */ - restore_flags(flags); + spin_unlock_irqrestore(&ep7211_lock, flags); } /* -- cgit v1.2.3 From a85d771e32f9724b61a68748cc667d1e11fe3478 Mon Sep 17 00:00:00 2001 From: Christophe Lucas Date: Mon, 20 Mar 2006 19:00:27 -0800 Subject: [IRDA]: pci_register_driver conversion This patch converts 2 IrDA drivers pci_module_init() calls to pci_register_driver(). Signed-off-by: Christophe Lucas Signed-off-by: Domen Puncer Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/donauboe.c | 2 +- drivers/net/irda/vlsi_ir.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 3137592d60c..910c0cab35b 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -1778,7 +1778,7 @@ static struct pci_driver donauboe_pci_driver = { static int __init donauboe_init (void) { - return pci_module_init(&donauboe_pci_driver); + return pci_register_driver(&donauboe_pci_driver); } static void __exit diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index a9f49f058cf..97a49e0be76 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -1887,7 +1887,7 @@ static int __init vlsi_mod_init(void) vlsi_proc_root->owner = THIS_MODULE; } - ret = pci_module_init(&vlsi_irda_driver); + ret = pci_register_driver(&vlsi_irda_driver); if (ret && vlsi_proc_root) remove_proc_entry(PROC_DIR, NULL); -- cgit v1.2.3 From e75f7c900944aa90831f6d343ca40090a68b56dd Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 21:33:26 -0800 Subject: [TG3]: Add some missing netif_running() checks Add missing netif_running() checks in tg3's dev->set_multicast_list() and dev->set_mac_address(). If not netif_running(), these 2 calls can simply return 0 after storing the new settings if required. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 994658d26b8..f7da3bf2fa0 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -5537,6 +5537,9 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p) memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); + if (!netif_running(dev)) + return 0; + spin_lock_bh(&tp->lock); __tg3_set_mac_addr(tp); spin_unlock_bh(&tp->lock); @@ -7192,6 +7195,9 @@ static void tg3_set_rx_mode(struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); + if (!netif_running(dev)) + return; + tg3_full_lock(tp, 0); __tg3_set_rx_mode(dev); tg3_full_unlock(tp); -- cgit v1.2.3 From 4f81c32b028aecd818634b1ef36aae3b2b3e66ce Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 21:33:42 -0800 Subject: [TG3]: Fix tg3_get_ringparam() Fix-up tg3_get_ringparam() to return the correct parameters. Set the jumbo rx ring parameter only if it is supported by the chip and currently in use. Add missing value for tx_max_pending, noticed by Rick Jones. Update version to 3.51. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f7da3bf2fa0..d4f5b58e1dd 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -69,8 +69,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.50" -#define DRV_MODULE_RELDATE "Feb 4, 2006" +#define DRV_MODULE_VERSION "3.51" +#define DRV_MODULE_RELDATE "Feb 21, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -7593,11 +7593,20 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam * ering->rx_max_pending = TG3_RX_RING_SIZE - 1; ering->rx_mini_max_pending = 0; - ering->rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1; + if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) + ering->rx_jumbo_max_pending = TG3_RX_JUMBO_RING_SIZE - 1; + else + ering->rx_jumbo_max_pending = 0; + + ering->tx_max_pending = TG3_TX_RING_SIZE - 1; ering->rx_pending = tp->rx_pending; ering->rx_mini_pending = 0; - ering->rx_jumbo_pending = tp->rx_jumbo_pending; + if (tp->tg3_flags & TG3_FLAG_JUMBO_RING_ENABLE) + ering->rx_jumbo_pending = tp->rx_jumbo_pending; + else + ering->rx_jumbo_pending = 0; + ering->tx_pending = tp->tx_pending; } -- cgit v1.2.3 From 0ac81ae34ec8898e7eb1388fe21e3cee7b626a88 Mon Sep 17 00:00:00 2001 From: David Basden Date: Mon, 20 Mar 2006 22:21:10 -0800 Subject: [IRDA]: TOIM3232 dongle support Here goes a patch for supporting TOIM3232 based serial IrDA dongles. The code is based on the tekram dongle code. It's been tested with a TOIM3232 based IRWave 320S dongle. It may work for TOIM4232 dongles, although it's not been tested. Signed-off-by: David Basden Signed-off-by: Samuel Ortiz Signed-off-by: David S. Miller --- drivers/net/irda/Kconfig | 8 + drivers/net/irda/Makefile | 1 + drivers/net/irda/toim3232-sir.c | 375 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 384 insertions(+) create mode 100644 drivers/net/irda/toim3232-sir.c (limited to 'drivers/net') diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index c81fe1c382d..5e6d0075299 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -64,6 +64,14 @@ config TEKRAM_DONGLE dongles you will have to start irattach like this: "irattach -d tekram". +config TOIM3232_DONGLE + tristate "TOIM3232 IrDa dongle" + depends on DONGLE && IRDA + help + Say Y here if you want to build support for the Vishay/Temic + TOIM3232 and TOIM4232 based dongles. + To compile it as a module, choose M here. + config LITELINK_DONGLE tristate "Parallax LiteLink dongle" depends on DONGLE && IRDA diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index 72cbfdc9cfc..27ab75f2079 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_OLD_BELKIN_DONGLE) += old_belkin-sir.o obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o +obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o # The SIR helper module sir-dev-objs := sir_dev.o sir_dongle.o sir_kthread.o diff --git a/drivers/net/irda/toim3232-sir.c b/drivers/net/irda/toim3232-sir.c new file mode 100644 index 00000000000..f6e5fed6a36 --- /dev/null +++ b/drivers/net/irda/toim3232-sir.c @@ -0,0 +1,375 @@ +/********************************************************************* + * + * Filename: toim3232-sir.c + * Version: 1.0 + * Description: Implementation of dongles based on the Vishay/Temic + * TOIM3232 SIR Endec chipset. Currently only the + * IRWave IR320ST-2 is tested, although it should work + * with any TOIM3232 or TOIM4232 chipset based RS232 + * dongle with minimal modification. + * Based heavily on the Tekram driver (tekram.c), + * with thanks to Dag Brattli and Martin Diehl. + * Status: Experimental. + * Author: David Basden + * Created at: Thu Feb 09 23:47:32 2006 + * + * Copyright (c) 2006 David Basden. + * Copyright (c) 1998-1999 Dag Brattli, + * Copyright (c) 2002 Martin Diehl, + * All Rights Reserved. + * + * 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. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +/* + * This driver has currently only been tested on the IRWave IR320ST-2 + * + * PROTOCOL: + * + * The protocol for talking to the TOIM3232 is quite easy, and is + * designed to interface with RS232 with only level convertors. The + * BR/~D line on the chip is brought high to signal 'command mode', + * where a command byte is sent to select the baudrate of the RS232 + * interface and the pulse length of the IRDA output. When BR/~D + * is brought low, the dongle then changes to the selected baudrate, + * and the RS232 interface is used for data until BR/~D is brought + * high again. The initial speed for the TOIMx323 after RESET is + * 9600 baud. The baudrate for command-mode is the last selected + * baud-rate, or 9600 after a RESET. + * + * The dongle I have (below) adds some extra hardware on the front end, + * but this is mostly directed towards pariasitic power from the RS232 + * line rather than changing very much about how to communicate with + * the TOIM3232. + * + * The protocol to talk to the TOIM4232 chipset seems to be almost + * identical to the TOIM3232 (and the 4232 datasheet is more detailed) + * so this code will probably work on that as well, although I haven't + * tested it on that hardware. + * + * Target dongle variations that might be common: + * + * DTR and RTS function: + * The data sheet for the 4232 has a sample implementation that hooks the + * DTR and RTS lines to the RESET and BaudRate/~Data lines of the + * chip (through line-converters). Given both DTR and RTS would have to + * be held low in normal operation, and the TOIMx232 requires +5V to + * signal ground, most dongle designers would almost certainly choose + * an implementation that kept at least one of DTR or RTS high in + * normal operation to provide power to the dongle, but will likely + * vary between designs. + * + * User specified command bits: + * There are two user-controllable output lines from the TOIMx232 that + * can be set low or high by setting the appropriate bits in the + * high-nibble of the command byte (when setting speed and pulse length). + * These might be used to switch on and off added hardware or extra + * dongle features. + * + * + * Target hardware: IRWave IR320ST-2 + * + * The IRWave IR320ST-2 is a simple dongle based on the Vishay/Temic + * TOIM3232 SIR Endec and the Vishay/Temic TFDS4500 SIR IRDA transciever. + * It uses a hex inverter and some discrete components to buffer and + * line convert the RS232 down to 5V. + * + * The dongle is powered through a voltage regulator, fed by a large + * capacitor. To switch the dongle on, DTR is brought high to charge + * the capacitor and drive the voltage regulator. DTR isn't associated + * with any control lines on the TOIM3232. Parisitic power is also taken + * from the RTS, TD and RD lines when brought high, but through resistors. + * When DTR is low, the circuit might lose power even with RTS high. + * + * RTS is inverted and attached to the BR/~D input pin. When RTS + * is high, BR/~D is low, and the TOIM3232 is in the normal 'data' mode. + * RTS is brought low, BR/~D is high, and the TOIM3232 is in 'command + * mode'. + * + * For some unknown reason, the RESET line isn't actually connected + * to anything. This means to reset the dongle to get it to a known + * state (9600 baud) you must drop DTR and RTS low, wait for the power + * capacitor to discharge, and then bring DTR (and RTS for data mode) + * high again, and wait for the capacitor to charge, the power supply + * to stabilise, and the oscillator clock to stabilise. + * + * Fortunately, if the current baudrate is known, the chipset can + * easily change speed by entering command mode without having to + * reset the dongle first. + * + * Major Components: + * + * - Vishay/Temic TOIM3232 SIR Endec to change RS232 pulse timings + * to IRDA pulse timings + * - 3.6864MHz crystal to drive TOIM3232 clock oscillator + * - DM74lS04M Inverting Hex line buffer for RS232 input buffering + * and level conversion + * - PJ2951AC 150mA voltage regulator + * - Vishay/Temic TFDS4500 SIR IRDA front-end transceiver + * + */ + +#include +#include +#include + +#include + +#include "sir-dev.h" + +MODULE_PARM(toim3232delay, "i"); +MODULE_PARM_DESC(toim3232delay, "toim3232 dongle write complete delay"); +static int toim3232delay = 150; /* default is 150 ms */ + +#if 0 +MODULE_PARM(toim3232flipdtr, "i"); +MODULE_PARM_DESC(toim3232flipdtr, "toim3232 dongle invert DTR (Reset)"); +static int toim3232flipdtr = 0; /* default is DTR high to reset */ + +MODULE_PARM(toim3232fliptrs, "i"); +MODULE_PARM_DESC(toim3232fliprts, "toim3232 dongle invert RTS (BR/D)"); +static int toim3232fliprts = 0; /* default is RTS high for baud change */ +#endif + +static int toim3232_open(struct sir_dev *); +static int toim3232_close(struct sir_dev *); +static int toim3232_change_speed(struct sir_dev *, unsigned); +static int toim3232_reset(struct sir_dev *); + +#define TOIM3232_115200 0x00 +#define TOIM3232_57600 0x01 +#define TOIM3232_38400 0x02 +#define TOIM3232_19200 0x03 +#define TOIM3232_9600 0x06 +#define TOIM3232_2400 0x0A + +#define TOIM3232_PW 0x10 /* Pulse select bit */ + +static struct dongle_driver toim3232 = { + .owner = THIS_MODULE, + .driver_name = "Vishay TOIM3232", + .type = IRDA_TOIM3232_DONGLE, + .open = toim3232_open, + .close = toim3232_close, + .reset = toim3232_reset, + .set_speed = toim3232_change_speed, +}; + +static int __init toim3232_sir_init(void) +{ + if (toim3232delay < 1 || toim3232delay > 500) + toim3232delay = 200; + IRDA_DEBUG(1, "%s - using %d ms delay\n", + toim3232.driver_name, toim3232delay); + return irda_register_dongle(&toim3232); +} + +static void __exit toim3232_sir_cleanup(void) +{ + irda_unregister_dongle(&toim3232); +} + +static int toim3232_open(struct sir_dev *dev) +{ + struct qos_info *qos = &dev->qos; + + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + + /* Pull the lines high to start with. + * + * For the IR320ST-2, we need to charge the main supply capacitor to + * switch the device on. We keep DTR high throughout to do this. + * When RTS, TD and RD are high, they will also trickle-charge the + * cap. RTS is high for data transmission, and low for baud rate select. + * -- DGB + */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* The TOI3232 supports many speeds between 1200bps and 115000bps. + * We really only care about those supported by the IRDA spec, but + * 38400 seems to be implemented in many places */ + qos->baud_rate.bits &= IR_2400|IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; + + /* From the tekram driver. Not sure what a reasonable value is -- DGB */ + qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */ + irda_qos_bits_to_value(qos); + + /* irda thread waits 50 msec for power settling */ + + return 0; +} + +static int toim3232_close(struct sir_dev *dev) +{ + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + + /* Power off dongle */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + + return 0; +} + +/* + * Function toim3232change_speed (dev, state, speed) + * + * Set the speed for the TOIM3232 based dongle. Warning, this + * function must be called with a process context! + * + * Algorithm + * 1. keep DTR high but clear RTS to bring into baud programming mode + * 2. wait at least 7us to enter programming mode + * 3. send control word to set baud rate and timing + * 4. wait at least 1us + * 5. bring RTS high to enter DATA mode (RS232 is passed through to transceiver) + * 6. should take effect immediately (although probably worth waiting) + */ + +#define TOIM3232_STATE_WAIT_SPEED (SIRDEV_STATE_DONGLE_SPEED + 1) + +static int toim3232_change_speed(struct sir_dev *dev, unsigned speed) +{ + unsigned state = dev->fsm.substate; + unsigned delay = 0; + u8 byte; + static int ret = 0; + + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + + switch(state) { + case SIRDEV_STATE_DONGLE_SPEED: + + /* Figure out what we are going to send as a control byte */ + switch (speed) { + case 2400: + byte = TOIM3232_PW|TOIM3232_2400; + break; + default: + speed = 9600; + ret = -EINVAL; + /* fall thru */ + case 9600: + byte = TOIM3232_PW|TOIM3232_9600; + break; + case 19200: + byte = TOIM3232_PW|TOIM3232_19200; + break; + case 38400: + byte = TOIM3232_PW|TOIM3232_38400; + break; + case 57600: + byte = TOIM3232_PW|TOIM3232_57600; + break; + case 115200: + byte = TOIM3232_115200; + break; + } + + /* Set DTR, Clear RTS: Go into baud programming mode */ + sirdev_set_dtr_rts(dev, TRUE, FALSE); + + /* Wait at least 7us */ + udelay(14); + + /* Write control byte */ + sirdev_raw_write(dev, &byte, 1); + + dev->speed = speed; + + state = TOIM3232_STATE_WAIT_SPEED; + delay = toim3232delay; + break; + + case TOIM3232_STATE_WAIT_SPEED: + /* Have transmitted control byte * Wait for 'at least 1us' */ + udelay(14); + + /* Set DTR, Set RTS: Go into normal data mode */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Wait (TODO: check this is needed) */ + udelay(50); + break; + + default: + printk(KERN_ERR "%s - undefined state %d\n", __FUNCTION__, state); + ret = -EINVAL; + break; + } + + dev->fsm.substate = state; + return (delay > 0) ? delay : ret; +} + +/* + * Function toim3232reset (driver) + * + * This function resets the toim3232 dongle. Warning, this function + * must be called with a process context!! + * + * What we should do is: + * 0. Pull RESET high + * 1. Wait for at least 7us + * 2. Pull RESET low + * 3. Wait for at least 7us + * 4. Pull BR/~D high + * 5. Wait for at least 7us + * 6. Send control byte to set baud rate + * 7. Wait at least 1us after stop bit + * 8. Pull BR/~D low + * 9. Should then be in data mode + * + * Because the IR320ST-2 doesn't have the RESET line connected for some reason, + * we'll have to do something else. + * + * The default speed after a RESET is 9600, so lets try just bringing it up in + * data mode after switching it off, waiting for the supply capacitor to + * discharge, and then switch it back on. This isn't actually pulling RESET + * high, but it seems to have the same effect. + * + * This behaviour will probably work on dongles that have the RESET line connected, + * but if not, add a flag for the IR320ST-2, and implment the above-listed proper + * behaviour. + * + * RTS is inverted and then fed to BR/~D, so to put it in programming mode, we + * need to have pull RTS low + */ + +static int toim3232_reset(struct sir_dev *dev) +{ + IRDA_DEBUG(2, "%s()\n", __FUNCTION__); + + /* Switch off both DTR and RTS to switch off dongle */ + sirdev_set_dtr_rts(dev, FALSE, FALSE); + + /* Should sleep a while. This might be evil doing it this way.*/ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(50)); + + /* Set DTR, Set RTS (data mode) */ + sirdev_set_dtr_rts(dev, TRUE, TRUE); + + /* Wait at least 10 ms for power to stabilize again */ + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(10)); + + /* Speed should now be 9600 */ + dev->speed = 9600; + + return 0; +} + +MODULE_AUTHOR("David Basden "); +MODULE_DESCRIPTION("Vishay/Temic TOIM3232 based dongle driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("irda-dongle-12"); /* IRDA_TOIM3232_DONGLE */ + +module_init(toim3232_sir_init); +module_exit(toim3232_sir_cleanup); -- cgit v1.2.3 From 6756ae4b4e97aba48c042b4aa6b77a18f507d2cb Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 20 Mar 2006 22:23:58 -0800 Subject: [NET]: Convert RTNL to mutex. This patch turns the RTNL from a semaphore to a new 2.6.16 mutex and gets rid of some of the leftover legacy. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- drivers/net/8139too.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index e58d4c50c2e..f5ee064ab6b 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -1605,7 +1605,7 @@ static void rtl8139_thread (void *_data) if (tp->watchdog_fired) { tp->watchdog_fired = 0; rtl8139_tx_timeout_task(_data); - } else if (rtnl_shlock_nowait() == 0) { + } else if (rtnl_trylock()) { rtl8139_thread_iter (dev, tp, tp->mmio_addr); rtnl_unlock (); } else { -- cgit v1.2.3 From d9ab5ad12b0d865bdb1b750d81192d34465541e9 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 22:27:35 -0800 Subject: [TG3]: Add 5787 and 5754 basic support Add basic support for 2 new chips 5787 and 5754. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 27 +++++++++++++++++++++++++-- drivers/net/tg3.h | 6 +++++- 2 files changed, 30 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d4f5b58e1dd..e6ed940d771 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -221,6 +221,14 @@ static struct pci_device_id tg3_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5753F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5714S, @@ -4388,6 +4396,10 @@ static int tg3_chip_reset(struct tg3 *tp) tp->nvram_lock_cnt = 0; } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + tw32(GRC_FASTBOOT_PC, 0); + /* * We must avoid the readl() that normally takes place. * It locks machines, causes machine checks, and other @@ -6018,6 +6030,10 @@ static int tg3_reset_hw(struct tg3 *tp) } } + /* Enable host coalescing bug fix */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + val |= (1 << 29); + tw32_f(WDMAC_MODE, val); udelay(40); @@ -8326,6 +8342,9 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, if (!err) tg3_nvram_unlock(tp); + if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) + tg3_phy_reset(tp); + if (tg3_test_registers(tp) != 0) { etest->flags |= ETH_TEST_FL_FAILED; data[2] = 1; @@ -9681,6 +9700,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; @@ -9693,7 +9713,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0) @@ -9903,7 +9924,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG; - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) + if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787)) tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG; tp->coalesce_mode = 0; @@ -10628,6 +10650,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5752: return "5752"; case PHY_ID_BCM5714: return "5714"; case PHY_ID_BCM5780: return "5780"; + case PHY_ID_BCM5787: return "5787"; case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; default: return "unknown"; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 7e3b613afb2..8d32fbe0d30 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -138,6 +138,7 @@ #define ASIC_REV_5752 0x06 #define ASIC_REV_5780 0x08 #define ASIC_REV_5714 0x09 +#define ASIC_REV_5787 0x0b #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -1393,6 +1394,7 @@ #define GRC_MDI_CTRL 0x00006844 #define GRC_SEEPROM_DELAY 0x00006848 /* 0x684c --> 0x6c00 unused */ +#define GRC_FASTBOOT_PC 0x00006894 /* 5752, 5755, 5787 */ /* 0x6c00 --> 0x7000 unused */ @@ -2247,6 +2249,7 @@ struct tg3 { #define PHY_ID_BCM5752 0x60008100 #define PHY_ID_BCM5714 0x60008340 #define PHY_ID_BCM5780 0x60008350 +#define PHY_ID_BCM5787 0xbc050ce0 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff #define PHY_ID_REV_MASK 0x0000000f @@ -2271,7 +2274,8 @@ struct tg3 { (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \ (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \ (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \ - (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM8002) + (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \ + (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; -- cgit v1.2.3 From 1b27777a9b9b2b6d1c06000b7a31262d198b4238 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 22:27:48 -0800 Subject: [TG3]: Add 5787 nvram support Support additional nvrams and new nvram format for 5787 and 5754. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++-------- drivers/net/tg3.h | 7 +++ 2 files changed, 130 insertions(+), 20 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e6ed940d771..9cd8613625f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7816,29 +7816,53 @@ static void tg3_get_ethtool_stats (struct net_device *dev, } #define NVRAM_TEST_SIZE 0x100 +#define NVRAM_SELFBOOT_FORMAT1_SIZE 0x14 static int tg3_test_nvram(struct tg3 *tp) { - u32 *buf, csum; - int i, j, err = 0; + u32 *buf, csum, magic; + int i, j, err = 0, size; - buf = kmalloc(NVRAM_TEST_SIZE, GFP_KERNEL); + if (tg3_nvram_read(tp, 0, &magic) != 0) + return -EIO; + + magic = swab32(magic); + if (magic == TG3_EEPROM_MAGIC) + size = NVRAM_TEST_SIZE; + else if ((magic & 0xff000000) == 0xa5000000) { + if ((magic & 0xe00000) == 0x200000) + size = NVRAM_SELFBOOT_FORMAT1_SIZE; + else + return 0; + } else + return -EIO; + + buf = kmalloc(size, GFP_KERNEL); if (buf == NULL) return -ENOMEM; - for (i = 0, j = 0; i < NVRAM_TEST_SIZE; i += 4, j++) { + err = -EIO; + for (i = 0, j = 0; i < size; i += 4, j++) { u32 val; if ((err = tg3_nvram_read(tp, i, &val)) != 0) break; buf[j] = cpu_to_le32(val); } - if (i < NVRAM_TEST_SIZE) + if (i < size) goto out; - err = -EIO; - if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC) - goto out; + /* Selfboot format */ + if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC) { + u8 *buf8 = (u8 *) buf, csum8 = 0; + + for (i = 0; i < size; i++) + csum8 += buf8[i]; + + if (csum8 == 0) + return 0; + return -EIO; + } /* Bootstrap checksum at offset 0x10 */ csum = calc_crc((unsigned char *) buf, 0x10); @@ -8561,14 +8585,15 @@ static struct ethtool_ops tg3_ethtool_ops = { static void __devinit tg3_get_eeprom_size(struct tg3 *tp) { - u32 cursize, val; + u32 cursize, val, magic; tp->nvram_size = EEPROM_CHIP_SIZE; if (tg3_nvram_read(tp, 0, &val) != 0) return; - if (swab32(val) != TG3_EEPROM_MAGIC) + magic = swab32(val); + if ((magic != TG3_EEPROM_MAGIC) && ((magic & 0xff000000) != 0xa5000000)) return; /* @@ -8576,13 +8601,13 @@ static void __devinit tg3_get_eeprom_size(struct tg3 *tp) * When we encounter our validation signature, we know the addressing * has wrapped around, and thus have our chip size. */ - cursize = 0x800; + cursize = 0x10; while (cursize < tp->nvram_size) { if (tg3_nvram_read(tp, cursize, &val) != 0) return; - if (swab32(val) == TG3_EEPROM_MAGIC) + if (swab32(val) == magic) break; cursize <<= 1; @@ -8595,6 +8620,15 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp) { u32 val; + if (tg3_nvram_read(tp, 0, &val) != 0) + return; + + /* Selfboot format */ + if (swab32(val) != TG3_EEPROM_MAGIC) { + tg3_get_eeprom_size(tp); + return; + } + if (tg3_nvram_read(tp, 0xf0, &val) == 0) { if (val != 0) { tp->nvram_size = (val >> 16) * 1024; @@ -8718,6 +8752,44 @@ static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp) } } +static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp) +{ + u32 nvcfg1; + + nvcfg1 = tr32(NVRAM_CFG1); + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5787VENDOR_ATMEL_EEPROM_64KHZ: + case FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ: + case FLASH_5787VENDOR_MICRO_EEPROM_64KHZ: + case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + break; + case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: + case FLASH_5755VENDOR_ATMEL_FLASH_1: + case FLASH_5755VENDOR_ATMEL_FLASH_2: + case FLASH_5755VENDOR_ATMEL_FLASH_3: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 264; + break; + case FLASH_5752VENDOR_ST_M45PE10: + case FLASH_5752VENDOR_ST_M45PE20: + case FLASH_5752VENDOR_ST_M45PE40: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 256; + break; + } +} + /* Chips other than 5700/5701 use the NVRAM for fetching info. */ static void __devinit tg3_nvram_init(struct tg3 *tp) { @@ -8753,6 +8825,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tg3_get_5752_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + tg3_get_5787_nvram_info(tp); else tg3_get_nvram_info(tp); @@ -9041,6 +9115,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, nvram_cmd |= NVRAM_CMD_LAST; if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) && (tp->nvram_jedecnum == JEDEC_ST) && (nvram_cmd & NVRAM_CMD_FIRST)) { @@ -9444,6 +9519,7 @@ static void __devinit tg3_read_partno(struct tg3 *tp) { unsigned char vpd_data[256]; int i; + u32 magic; if (tp->tg3_flags2 & TG3_FLG2_SUN_570X) { /* Sun decided not to put the necessary bits in the @@ -9453,16 +9529,43 @@ static void __devinit tg3_read_partno(struct tg3 *tp) return; } - for (i = 0; i < 256; i += 4) { - u32 tmp; + if (tg3_nvram_read(tp, 0x0, &magic)) + return; - if (tg3_nvram_read(tp, 0x100 + i, &tmp)) - goto out_not_found; + if (swab32(magic) == TG3_EEPROM_MAGIC) { + for (i = 0; i < 256; i += 4) { + u32 tmp; - vpd_data[i + 0] = ((tmp >> 0) & 0xff); - vpd_data[i + 1] = ((tmp >> 8) & 0xff); - vpd_data[i + 2] = ((tmp >> 16) & 0xff); - vpd_data[i + 3] = ((tmp >> 24) & 0xff); + if (tg3_nvram_read(tp, 0x100 + i, &tmp)) + goto out_not_found; + + vpd_data[i + 0] = ((tmp >> 0) & 0xff); + vpd_data[i + 1] = ((tmp >> 8) & 0xff); + vpd_data[i + 2] = ((tmp >> 16) & 0xff); + vpd_data[i + 3] = ((tmp >> 24) & 0xff); + } + } else { + int vpd_cap; + + vpd_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_VPD); + for (i = 0; i < 256; i += 4) { + u32 tmp, j = 0; + u16 tmp16; + + pci_write_config_word(tp->pdev, vpd_cap + PCI_VPD_ADDR, + i); + while (j++ < 100) { + pci_read_config_word(tp->pdev, vpd_cap + + PCI_VPD_ADDR, &tmp16); + if (tmp16 & 0x8000) + break; + msleep(1); + } + pci_read_config_dword(tp->pdev, vpd_cap + PCI_VPD_DATA, + &tmp); + tmp = cpu_to_le32(tmp); + memcpy(&vpd_data[i], &tmp, 4); + } } /* Now parse and find the part number. */ diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 8d32fbe0d30..6a0d2fa0574 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1438,6 +1438,13 @@ #define FLASH_5752VENDOR_ST_M45PE10 0x02400000 #define FLASH_5752VENDOR_ST_M45PE20 0x02400002 #define FLASH_5752VENDOR_ST_M45PE40 0x02400001 +#define FLASH_5755VENDOR_ATMEL_FLASH_1 0x03400001 +#define FLASH_5755VENDOR_ATMEL_FLASH_2 0x03400002 +#define FLASH_5755VENDOR_ATMEL_FLASH_3 0x03400000 +#define FLASH_5787VENDOR_ATMEL_EEPROM_64KHZ 0x03000003 +#define FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ 0x03000002 +#define FLASH_5787VENDOR_MICRO_EEPROM_64KHZ 0x03000000 +#define FLASH_5787VENDOR_MICRO_EEPROM_376KHZ 0x02000000 #define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000 #define FLASH_5752PAGE_SIZE_256 0x00000000 #define FLASH_5752PAGE_SIZE_512 0x10000000 -- cgit v1.2.3 From 5a6f3074c2ea5a7b4ff5b18f0e1fd9b1257e1a29 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 22:28:05 -0800 Subject: [TG3]: Add new hard_start_xmit Support 5787 hardware TSO using a new flag TG3_FLG2_HW_TSO_2. Since the TSO interface is slightly different and these chips have finally fixed the 4GB DMA problem and do not have the 40-bit DMA problem, a new hard_start_xmit is used for these chips. All previous chips will use the old hard_start_xmit that is now renamed tg3_start_xmit_dma_bug(). Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- drivers/net/tg3.h | 4 +- 2 files changed, 142 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 9cd8613625f..d4035de6440 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3655,7 +3655,135 @@ static void tg3_set_txd(struct tg3 *tp, int entry, txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; } +/* hard_start_xmit for devices that don't have any bugs and + * support TG3_FLG2_HW_TSO_2 only. + */ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct tg3 *tp = netdev_priv(dev); + dma_addr_t mapping; + u32 len, entry, base_flags, mss; + + len = skb_headlen(skb); + + /* No BH disabling for tx_lock here. We are running in BH disabled + * context and TX reclaim runs via tp->poll inside of a software + * interrupt. Furthermore, IRQ processing runs lockless so we have + * no IRQ context deadlocks to worry about either. Rejoice! + */ + if (!spin_trylock(&tp->tx_lock)) + return NETDEV_TX_LOCKED; + + if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) { + if (!netif_queue_stopped(dev)) { + netif_stop_queue(dev); + + /* This is a hard error, log it. */ + printk(KERN_ERR PFX "%s: BUG! Tx Ring full when " + "queue awake!\n", dev->name); + } + spin_unlock(&tp->tx_lock); + return NETDEV_TX_BUSY; + } + + entry = tp->tx_prod; + base_flags = 0; +#if TG3_TSO_SUPPORT != 0 + mss = 0; + if (skb->len > (tp->dev->mtu + ETH_HLEN) && + (mss = skb_shinfo(skb)->tso_size) != 0) { + int tcp_opt_len, ip_tcp_len; + + if (skb_header_cloned(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { + dev_kfree_skb(skb); + goto out_unlock; + } + + tcp_opt_len = ((skb->h.th->doff - 5) * 4); + ip_tcp_len = (skb->nh.iph->ihl * 4) + sizeof(struct tcphdr); + + base_flags |= (TXD_FLAG_CPU_PRE_DMA | + TXD_FLAG_CPU_POST_DMA); + + skb->nh.iph->check = 0; + skb->nh.iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len); + + skb->h.th->check = 0; + + mss |= (ip_tcp_len + tcp_opt_len) << 9; + } + else if (skb->ip_summed == CHECKSUM_HW) + base_flags |= TXD_FLAG_TCPUDP_CSUM; +#else + mss = 0; + if (skb->ip_summed == CHECKSUM_HW) + base_flags |= TXD_FLAG_TCPUDP_CSUM; +#endif +#if TG3_VLAN_TAG_USED + if (tp->vlgrp != NULL && vlan_tx_tag_present(skb)) + base_flags |= (TXD_FLAG_VLAN | + (vlan_tx_tag_get(skb) << 16)); +#endif + + /* Queue skb data, a.k.a. the main skb fragment. */ + mapping = pci_map_single(tp->pdev, skb->data, len, PCI_DMA_TODEVICE); + + tp->tx_buffers[entry].skb = skb; + pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); + + tg3_set_txd(tp, entry, mapping, len, base_flags, + (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); + + entry = NEXT_TX(entry); + + /* Now loop through additional data fragments, and queue them. */ + if (skb_shinfo(skb)->nr_frags > 0) { + unsigned int i, last; + + last = skb_shinfo(skb)->nr_frags - 1; + for (i = 0; i <= last; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + + len = frag->size; + mapping = pci_map_page(tp->pdev, + frag->page, + frag->page_offset, + len, PCI_DMA_TODEVICE); + + tp->tx_buffers[entry].skb = NULL; + pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); + + tg3_set_txd(tp, entry, mapping, len, + base_flags, (i == last) | (mss << 1)); + + entry = NEXT_TX(entry); + } + } + + /* Packets are ready, update Tx producer idx local and on card. */ + tw32_tx_mbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); + + tp->tx_prod = entry; + if (TX_BUFFS_AVAIL(tp) <= (MAX_SKB_FRAGS + 1)) { + netif_stop_queue(dev); + if (TX_BUFFS_AVAIL(tp) > TG3_TX_WAKEUP_THRESH) + netif_wake_queue(tp->dev); + } + +out_unlock: + mmiowb(); + spin_unlock(&tp->tx_lock); + + dev->trans_start = jiffies; + + return NETDEV_TX_OK; +} + +/* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and + * support TG3_FLG2_HW_TSO_1 or firmware TSO only. + */ +static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev) { struct tg3 *tp = netdev_priv(dev); dma_addr_t mapping; @@ -9811,8 +9939,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; - if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) - tp->tg3_flags2 |= TG3_FLG2_HW_TSO; + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; + else + tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1; + } if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && @@ -10163,10 +10295,13 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) else tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES; - /* It seems all chips can get confused if TX buffers + /* All chips before 5787 can get confused if TX buffers * straddle the 4GB address boundary in some cases. */ - tp->dev->hard_start_xmit = tg3_start_xmit; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + tp->dev->hard_start_xmit = tg3_start_xmit; + else + tp->dev->hard_start_xmit = tg3_start_xmit_dma_bug; tp->rx_offset = 2; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 && diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 6a0d2fa0574..ba3466c8a96 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2194,7 +2194,7 @@ struct tg3 { #define TG3_FLG2_PHY_SERDES 0x00002000 #define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000 #define TG3_FLG2_FLASH 0x00008000 -#define TG3_FLG2_HW_TSO 0x00010000 +#define TG3_FLG2_HW_TSO_1 0x00010000 #define TG3_FLG2_SERDES_PREEMPHASIS 0x00020000 #define TG3_FLG2_5705_PLUS 0x00040000 #define TG3_FLG2_5750_PLUS 0x00080000 @@ -2207,6 +2207,8 @@ struct tg3 { #define TG3_FLG2_PARALLEL_DETECT 0x01000000 #define TG3_FLG2_ICH_WORKAROUND 0x02000000 #define TG3_FLG2_5780_CLASS 0x04000000 +#define TG3_FLG2_HW_TSO_2 0x08000000 +#define TG3_FLG2_HW_TSO (TG3_FLG2_HW_TSO_1 | TG3_FLG2_HW_TSO_2) u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 -- cgit v1.2.3 From 9c27dbdf64cba05d0cacc343118a7fd01d4b82f7 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 22:28:27 -0800 Subject: [TG3]: Add ipv6 checksum support Support ipv6 tx csum on 5787 by setting NETIF_F_HW_CSUM. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index d4035de6440..5182a3be7f2 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7871,10 +7871,10 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) return 0; } - if (data) - dev->features |= NETIF_F_IP_CSUM; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + ethtool_op_set_tx_hw_csum(dev, data); else - dev->features &= ~NETIF_F_IP_CSUM; + ethtool_op_set_tx_csum(dev, data); return 0; } @@ -11236,7 +11236,11 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, * checksumming. */ if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) { - dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + dev->features |= NETIF_F_HW_CSUM; + else + dev->features |= NETIF_F_IP_CSUM; + dev->features |= NETIF_F_SG; tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; } else tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS; -- cgit v1.2.3 From fcfa0a32c767219c1bdad621ef4a3aff1904cbbd Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 22:28:41 -0800 Subject: [TG3]: Add new one-shot MSI handler Support one-shot MSI on 5787. This one-shot MSI idea is credited to David Miller. In this mode, MSI disables itself automatically after it is generated, saving the driver a register access to disable it for NAPI. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 85 +++++++++++++++++++++++++++++++++++-------------------- drivers/net/tg3.h | 1 + 2 files changed, 55 insertions(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5182a3be7f2..40f52897cf9 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -546,6 +546,9 @@ static void tg3_enable_ints(struct tg3 *tp) (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, (tp->last_tag << 24)); + if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) + tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, + (tp->last_tag << 24)); tg3_cond_int(tp); } @@ -3365,6 +3368,23 @@ static inline void tg3_full_unlock(struct tg3 *tp) spin_unlock_bh(&tp->lock); } +/* One-shot MSI handler - Chip automatically disables interrupt + * after sending MSI so driver doesn't have to do it. + */ +static irqreturn_t tg3_msi_1shot(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct tg3 *tp = netdev_priv(dev); + + prefetch(tp->hw_status); + prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); + + if (likely(!tg3_irq_sync(tp))) + netif_rx_schedule(dev); /* schedule NAPI poll */ + + return IRQ_HANDLED; +} + /* MSI ISR - No need to check for interrupt sharing and no need to * flush status block and interrupt mailbox. PCI ordering rules * guarantee that MSI will arrive after the status block. @@ -6511,6 +6531,26 @@ static void tg3_timer(unsigned long __opaque) add_timer(&tp->timer); } +int tg3_request_irq(struct tg3 *tp) +{ + irqreturn_t (*fn)(int, void *, struct pt_regs *); + unsigned long flags; + struct net_device *dev = tp->dev; + + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + fn = tg3_msi; + if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) + fn = tg3_msi_1shot; + flags = SA_SAMPLE_RANDOM; + } else { + fn = tg3_interrupt; + if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) + fn = tg3_interrupt_tagged; + flags = SA_SHIRQ | SA_SAMPLE_RANDOM; + } + return (request_irq(tp->pdev->irq, fn, flags, dev->name, dev)); +} + static int tg3_test_interrupt(struct tg3 *tp) { struct net_device *dev = tp->dev; @@ -6547,16 +6587,7 @@ static int tg3_test_interrupt(struct tg3 *tp) free_irq(tp->pdev->irq, dev); - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) - err = request_irq(tp->pdev->irq, tg3_msi, - SA_SAMPLE_RANDOM, dev->name, dev); - else { - irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt; - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) - fn = tg3_interrupt_tagged; - err = request_irq(tp->pdev->irq, fn, - SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); - } + err = tg3_request_irq(tp); if (err) return err; @@ -6608,14 +6639,7 @@ static int tg3_test_msi(struct tg3 *tp) tp->tg3_flags2 &= ~TG3_FLG2_USING_MSI; - { - irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt; - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) - fn = tg3_interrupt_tagged; - - err = request_irq(tp->pdev->irq, fn, - SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); - } + err = tg3_request_irq(tp); if (err) return err; @@ -6677,17 +6701,7 @@ static int tg3_open(struct net_device *dev) tp->tg3_flags2 |= TG3_FLG2_USING_MSI; } } - if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) - err = request_irq(tp->pdev->irq, tg3_msi, - SA_SAMPLE_RANDOM, dev->name, dev); - else { - irqreturn_t (*fn)(int, void *, struct pt_regs *)=tg3_interrupt; - if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) - fn = tg3_interrupt_tagged; - - err = request_irq(tp->pdev->irq, fn, - SA_SHIRQ | SA_SAMPLE_RANDOM, dev->name, dev); - } + err = tg3_request_irq(tp); if (err) { if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { @@ -6752,6 +6766,14 @@ static int tg3_open(struct net_device *dev) return err; } + + if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) { + if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) { + u32 val = tr32(0x7c04); + + tw32(0x7c04, val | (1 << 29)); + } + } } tg3_full_lock(tp, 0); @@ -9940,9 +9962,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) { tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; - else + tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; + } else tp->tg3_flags2 |= TG3_FLG2_HW_TSO_1; } diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index ba3466c8a96..6b05d5786cd 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2209,6 +2209,7 @@ struct tg3 { #define TG3_FLG2_5780_CLASS 0x04000000 #define TG3_FLG2_HW_TSO_2 0x08000000 #define TG3_FLG2_HW_TSO (TG3_FLG2_HW_TSO_1 | TG3_FLG2_HW_TSO_2) +#define TG3_FLG2_1SHOT_MSI 0x10000000 u32 split_mode_max_reqs; #define SPLIT_MODE_5704_MAX_REQ 3 -- cgit v1.2.3 From 79f4d13a15774c2d442b619bad95a4c612eed4f3 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 22:28:57 -0800 Subject: [TG3]: Fixup memory test for 5787 Ethtool memory test on 5787 requires a new memory table. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 40f52897cf9..fe5c565a528 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8306,14 +8306,24 @@ static int tg3_test_memory(struct tg3 *tp) { 0x00008000, 0x02000}, { 0x00010000, 0x0e000}, { 0xffffffff, 0x00000} + }, mem_tbl_5755[] = { + { 0x00000200, 0x00008}, + { 0x00004000, 0x00800}, + { 0x00006000, 0x00800}, + { 0x00008000, 0x02000}, + { 0x00010000, 0x0c000}, + { 0xffffffff, 0x00000} }; struct mem_entry *mem_tbl; int err = 0; int i; - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) - mem_tbl = mem_tbl_5705; - else + if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + mem_tbl = mem_tbl_5755; + else + mem_tbl = mem_tbl_5705; + } else mem_tbl = mem_tbl_570x; for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) { -- cgit v1.2.3 From 1820180b0e59cc48019414018b180518059f50d3 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 22:29:15 -0800 Subject: [TG3]: nvram cleanup Some nvram related cleanup: 1. Add a tg3_nvram_read_swab() since swabing the data is frequently done. 2. Add a function to convert nvram address to physical address instead of doing it in 2 separate places. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 62 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 27 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index fe5c565a528..602326b78ef 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7457,6 +7457,7 @@ static int tg3_get_eeprom_len(struct net_device *dev) } static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val); +static int tg3_nvram_read_swab(struct tg3 *tp, u32 offset, u32 *val); static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { @@ -7973,10 +7974,9 @@ static int tg3_test_nvram(struct tg3 *tp) u32 *buf, csum, magic; int i, j, err = 0, size; - if (tg3_nvram_read(tp, 0, &magic) != 0) + if (tg3_nvram_read_swab(tp, 0, &magic) != 0) return -EIO; - magic = swab32(magic); if (magic == TG3_EEPROM_MAGIC) size = NVRAM_TEST_SIZE; else if ((magic & 0xff000000) == 0xa5000000) { @@ -8749,10 +8749,9 @@ static void __devinit tg3_get_eeprom_size(struct tg3 *tp) tp->nvram_size = EEPROM_CHIP_SIZE; - if (tg3_nvram_read(tp, 0, &val) != 0) + if (tg3_nvram_read_swab(tp, 0, &magic) != 0) return; - magic = swab32(val); if ((magic != TG3_EEPROM_MAGIC) && ((magic & 0xff000000) != 0xa5000000)) return; @@ -8764,10 +8763,10 @@ static void __devinit tg3_get_eeprom_size(struct tg3 *tp) cursize = 0x10; while (cursize < tp->nvram_size) { - if (tg3_nvram_read(tp, cursize, &val) != 0) + if (tg3_nvram_read_swab(tp, cursize, &val) != 0) return; - if (swab32(val) == magic) + if (val == magic) break; cursize <<= 1; @@ -8780,11 +8779,11 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp) { u32 val; - if (tg3_nvram_read(tp, 0, &val) != 0) + if (tg3_nvram_read_swab(tp, 0, &val) != 0) return; /* Selfboot format */ - if (swab32(val) != TG3_EEPROM_MAGIC) { + if (val != TG3_EEPROM_MAGIC) { tg3_get_eeprom_size(tp); return; } @@ -9056,6 +9055,20 @@ static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd) return 0; } +static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr) +{ + if ((tp->tg3_flags & TG3_FLAG_NVRAM) && + (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && + (tp->tg3_flags2 & TG3_FLG2_FLASH) && + (tp->nvram_jedecnum == JEDEC_ATMEL)) + + addr = ((addr / tp->nvram_pagesize) << + ATMEL_AT45DB0X1B_PAGE_POS) + + (addr % tp->nvram_pagesize); + + return addr; +} + static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) { int ret; @@ -9068,14 +9081,7 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) if (!(tp->tg3_flags & TG3_FLAG_NVRAM)) return tg3_nvram_read_using_eeprom(tp, offset, val); - if ((tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && - (tp->tg3_flags2 & TG3_FLG2_FLASH) && - (tp->nvram_jedecnum == JEDEC_ATMEL)) { - - offset = ((offset / tp->nvram_pagesize) << - ATMEL_AT45DB0X1B_PAGE_POS) + - (offset % tp->nvram_pagesize); - } + offset = tg3_nvram_phys_addr(tp, offset); if (offset > NVRAM_ADDR_MSK) return -EINVAL; @@ -9100,6 +9106,16 @@ static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) return ret; } +static int tg3_nvram_read_swab(struct tg3 *tp, u32 offset, u32 *val) +{ + int err; + u32 tmp; + + err = tg3_nvram_read(tp, offset, &tmp); + *val = swab32(tmp); + return err; +} + static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp, u32 offset, u32 len, u8 *buf) { @@ -9252,15 +9268,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, page_off = offset % tp->nvram_pagesize; - if ((tp->tg3_flags2 & TG3_FLG2_FLASH) && - (tp->nvram_jedecnum == JEDEC_ATMEL)) { - - phy_addr = ((offset / tp->nvram_pagesize) << - ATMEL_AT45DB0X1B_PAGE_POS) + page_off; - } - else { - phy_addr = offset; - } + phy_addr = tg3_nvram_phys_addr(tp, offset); tw32(NVRAM_ADDR, phy_addr); @@ -9689,10 +9697,10 @@ static void __devinit tg3_read_partno(struct tg3 *tp) return; } - if (tg3_nvram_read(tp, 0x0, &magic)) + if (tg3_nvram_read_swab(tp, 0x0, &magic)) return; - if (swab32(magic) == TG3_EEPROM_MAGIC) { + if (magic == TG3_EEPROM_MAGIC) { for (i = 0; i < 256; i += 4) { u32 tmp; -- cgit v1.2.3 From c4e6575c78b83928c470d81b271909084a2efd37 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 22:29:32 -0800 Subject: [TG3]: Add firmware version info Add fw_version information to ethtool -i. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/net/tg3.h | 1 + 2 files changed, 57 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 602326b78ef..0a4e7b74c1f 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -7666,6 +7666,7 @@ static void tg3_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info strcpy(info->driver, DRV_MODULE_NAME); strcpy(info->version, DRV_MODULE_VERSION); + strcpy(info->fw_version, tp->fw_ver); strcpy(info->bus_info, pci_name(tp->pdev)); } @@ -9069,6 +9070,20 @@ static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr) return addr; } +static u32 tg3_nvram_logical_addr(struct tg3 *tp, u32 addr) +{ + if ((tp->tg3_flags & TG3_FLAG_NVRAM) && + (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) && + (tp->tg3_flags2 & TG3_FLG2_FLASH) && + (tp->nvram_jedecnum == JEDEC_ATMEL)) + + addr = ((addr >> ATMEL_AT45DB0X1B_PAGE_POS) * + tp->nvram_pagesize) + + (addr & ((1 << ATMEL_AT45DB0X1B_PAGE_POS) - 1)); + + return addr; +} + static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val) { int ret; @@ -9780,6 +9795,46 @@ out_not_found: strcpy(tp->board_part_number, "none"); } +static void __devinit tg3_read_fw_ver(struct tg3 *tp) +{ + u32 val, offset, start; + + if (tg3_nvram_read_swab(tp, 0, &val)) + return; + + if (val != TG3_EEPROM_MAGIC) + return; + + if (tg3_nvram_read_swab(tp, 0xc, &offset) || + tg3_nvram_read_swab(tp, 0x4, &start)) + return; + + offset = tg3_nvram_logical_addr(tp, offset); + if (tg3_nvram_read_swab(tp, offset, &val)) + return; + + if ((val & 0xfc000000) == 0x0c000000) { + u32 ver_offset, addr; + int i; + + if (tg3_nvram_read_swab(tp, offset + 4, &val) || + tg3_nvram_read_swab(tp, offset + 8, &ver_offset)) + return; + + if (val != 0) + return; + + addr = offset + ver_offset - start; + for (i = 0; i < 16; i += 4) { + if (tg3_nvram_read(tp, addr + i, &val)) + return; + + val = cpu_to_le32(val); + memcpy(tp->fw_ver + i, &val, 4); + } + } +} + #ifdef CONFIG_SPARC64 static int __devinit tg3_is_sun_570X(struct tg3 *tp) { @@ -10301,6 +10356,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } tg3_read_partno(tp); + tg3_read_fw_ver(tp); if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) { tp->tg3_flags &= ~TG3_FLAG_USE_MI_INTERRUPT; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 6b05d5786cd..baa34c4721d 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -2271,6 +2271,7 @@ struct tg3 { u32 led_ctrl; char board_part_number[24]; + char fw_ver[16]; u32 nic_sram_data_cfg; u32 pci_clock_ctrl; struct pci_dev *pdev_peer; -- cgit v1.2.3 From e9e678006ee865b0f7e53069b0e519141a710a6e Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 20 Mar 2006 22:29:52 -0800 Subject: [TG3]: update version and reldate Update version to 3.52. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 0a4e7b74c1f..e0691cf1645 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -69,8 +69,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.51" -#define DRV_MODULE_RELDATE "Feb 21, 2006" +#define DRV_MODULE_VERSION "3.52" +#define DRV_MODULE_RELDATE "Mar 06, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3 From 153330618691694af64f39fb56c9de051862380e Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 20 Mar 2006 22:32:28 -0800 Subject: [NET]: dev_put/dev_hold cleanup Get rid of the old __dev_put macro that is just a hold over from pre 2.6 kernel. And turn dev_hold into an inline instead of a macro. Signed-off-by: Stephen Hemminger Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/e1000/e1000_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index f39de16e6b9..49cd096a3c3 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -920,7 +920,7 @@ e1000_remove(struct pci_dev *pdev) unregister_netdev(netdev); #ifdef CONFIG_E1000_NAPI for (i = 0; i < adapter->num_rx_queues; i++) - __dev_put(&adapter->polling_netdev[i]); + dev_put(&adapter->polling_netdev[i]); #endif if (!e1000_check_phy_reset_block(&adapter->hw)) -- cgit v1.2.3 From d4ccd08cdfa8d34f4d25b62041343c52fc79385f Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Mon, 20 Mar 2006 22:32:53 -0800 Subject: [IRDA] sem2mutex: drivers/net/irda Semaphore to mutex conversion. The conversion was generated via scripts, and the result was validated automatically via a script as well. Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/irda/irtty-sir.c | 19 ++++++++++--------- drivers/net/irda/sir_dongle.c | 19 ++++++++++--------- 2 files changed, 20 insertions(+), 18 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 101750bf210..6a98b7ae497 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -338,7 +339,7 @@ static inline void irtty_stop_receiver(struct tty_struct *tty, int stop) /*****************************************************************/ /* serialize ldisc open/close with sir_dev */ -static DECLARE_MUTEX(irtty_sem); +static DEFINE_MUTEX(irtty_mutex); /* notifier from sir_dev when irda% device gets opened (ifup) */ @@ -348,11 +349,11 @@ static int irtty_start_dev(struct sir_dev *dev) struct tty_struct *tty; /* serialize with ldisc open/close */ - down(&irtty_sem); + mutex_lock(&irtty_mutex); priv = dev->priv; if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) { - up(&irtty_sem); + mutex_unlock(&irtty_mutex); return -ESTALE; } @@ -363,7 +364,7 @@ static int irtty_start_dev(struct sir_dev *dev) /* Make sure we can receive more data */ irtty_stop_receiver(tty, FALSE); - up(&irtty_sem); + mutex_unlock(&irtty_mutex); return 0; } @@ -375,11 +376,11 @@ static int irtty_stop_dev(struct sir_dev *dev) struct tty_struct *tty; /* serialize with ldisc open/close */ - down(&irtty_sem); + mutex_lock(&irtty_mutex); priv = dev->priv; if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) { - up(&irtty_sem); + mutex_unlock(&irtty_mutex); return -ESTALE; } @@ -390,7 +391,7 @@ static int irtty_stop_dev(struct sir_dev *dev) if (tty->driver->stop) tty->driver->stop(tty); - up(&irtty_sem); + mutex_unlock(&irtty_mutex); return 0; } @@ -514,13 +515,13 @@ static int irtty_open(struct tty_struct *tty) priv->dev = dev; /* serialize with start_dev - in case we were racing with ifup */ - down(&irtty_sem); + mutex_lock(&irtty_mutex); dev->priv = priv; tty->disc_data = priv; tty->receive_room = 65536; - up(&irtty_sem); + mutex_unlock(&irtty_mutex); IRDA_DEBUG(0, "%s - %s: irda line discipline opened\n", __FUNCTION__, tty->name); diff --git a/drivers/net/irda/sir_dongle.c b/drivers/net/irda/sir_dongle.c index 8d225921ae7..d7e32d9554f 100644 --- a/drivers/net/irda/sir_dongle.c +++ b/drivers/net/irda/sir_dongle.c @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -28,7 +29,7 @@ */ static LIST_HEAD(dongle_list); /* list of registered dongle drivers */ -static DECLARE_MUTEX(dongle_list_lock); /* protects the list */ +static DEFINE_MUTEX(dongle_list_lock); /* protects the list */ int irda_register_dongle(struct dongle_driver *new) { @@ -38,25 +39,25 @@ int irda_register_dongle(struct dongle_driver *new) IRDA_DEBUG(0, "%s : registering dongle \"%s\" (%d).\n", __FUNCTION__, new->driver_name, new->type); - down(&dongle_list_lock); + mutex_lock(&dongle_list_lock); list_for_each(entry, &dongle_list) { drv = list_entry(entry, struct dongle_driver, dongle_list); if (new->type == drv->type) { - up(&dongle_list_lock); + mutex_unlock(&dongle_list_lock); return -EEXIST; } } list_add(&new->dongle_list, &dongle_list); - up(&dongle_list_lock); + mutex_unlock(&dongle_list_lock); return 0; } EXPORT_SYMBOL(irda_register_dongle); int irda_unregister_dongle(struct dongle_driver *drv) { - down(&dongle_list_lock); + mutex_lock(&dongle_list_lock); list_del(&drv->dongle_list); - up(&dongle_list_lock); + mutex_unlock(&dongle_list_lock); return 0; } EXPORT_SYMBOL(irda_unregister_dongle); @@ -75,7 +76,7 @@ int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type) return -EBUSY; /* serialize access to the list of registered dongles */ - down(&dongle_list_lock); + mutex_lock(&dongle_list_lock); list_for_each(entry, &dongle_list) { drv = list_entry(entry, struct dongle_driver, dongle_list); @@ -109,14 +110,14 @@ int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type) if (!drv->open || (err=drv->open(dev))!=0) goto out_reject; /* failed to open driver */ - up(&dongle_list_lock); + mutex_unlock(&dongle_list_lock); return 0; out_reject: dev->dongle_drv = NULL; module_put(drv->owner); out_unlock: - up(&dongle_list_lock); + mutex_unlock(&dongle_list_lock); return err; } -- cgit v1.2.3 From 73a6c6306876c83ed992f1b15069a0ee9b3fa73b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Mon, 20 Mar 2006 22:33:41 -0800 Subject: [IRDA]: remove MODULE_PARM() MODULE_PARM() is deprecated and is about to go away altogether. Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/irda/toim3232-sir.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/toim3232-sir.c b/drivers/net/irda/toim3232-sir.c index f6e5fed6a36..aa1a9b0ed83 100644 --- a/drivers/net/irda/toim3232-sir.c +++ b/drivers/net/irda/toim3232-sir.c @@ -125,18 +125,18 @@ #include "sir-dev.h" -MODULE_PARM(toim3232delay, "i"); -MODULE_PARM_DESC(toim3232delay, "toim3232 dongle write complete delay"); static int toim3232delay = 150; /* default is 150 ms */ +module_param(toim3232delay, int, 0); +MODULE_PARM_DESC(toim3232delay, "toim3232 dongle write complete delay"); #if 0 -MODULE_PARM(toim3232flipdtr, "i"); -MODULE_PARM_DESC(toim3232flipdtr, "toim3232 dongle invert DTR (Reset)"); static int toim3232flipdtr = 0; /* default is DTR high to reset */ +module_param(toim3232flipdtr, int, 0); +MODULE_PARM_DESC(toim3232flipdtr, "toim3232 dongle invert DTR (Reset)"); -MODULE_PARM(toim3232fliptrs, "i"); -MODULE_PARM_DESC(toim3232fliprts, "toim3232 dongle invert RTS (BR/D)"); static int toim3232fliprts = 0; /* default is RTS high for baud change */ +module_param(toim3232fliptrs, int, 0); +MODULE_PARM_DESC(toim3232fliprts, "toim3232 dongle invert RTS (BR/D)"); #endif static int toim3232_open(struct sir_dev *); -- cgit v1.2.3 From 758df69ee01f7be99c2df5562ef278bab05623dd Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 20 Mar 2006 22:34:09 -0800 Subject: [CASSINI]: sem2mutex Semaphore to mutexes conversion. The conversion was generated via scripts, and the result was validated automatically via a script as well. Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/cassini.c | 40 ++++++++++++++++++++-------------------- drivers/net/cassini.h | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 6e295fce5c6..8f1573e658a 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -91,6 +91,7 @@ #include #include #include +#include #include @@ -3892,7 +3893,7 @@ static void cas_reset(struct cas *cp, int blkflag) spin_unlock(&cp->stat_lock[N_TX_RINGS]); } -/* Shut down the chip, must be called with pm_sem held. */ +/* Shut down the chip, must be called with pm_mutex held. */ static void cas_shutdown(struct cas *cp) { unsigned long flags; @@ -4311,11 +4312,11 @@ static int cas_open(struct net_device *dev) int hw_was_up, err; unsigned long flags; - down(&cp->pm_sem); + mutex_lock(&cp->pm_mutex); hw_was_up = cp->hw_running; - /* The power-management semaphore protects the hw_running + /* The power-management mutex protects the hw_running * etc. state so it is safe to do this bit without cp->lock */ if (!cp->hw_running) { @@ -4364,7 +4365,7 @@ static int cas_open(struct net_device *dev) cas_unlock_all_restore(cp, flags); netif_start_queue(dev); - up(&cp->pm_sem); + mutex_unlock(&cp->pm_mutex); return 0; err_spare: @@ -4372,7 +4373,7 @@ err_spare: cas_free_rxds(cp); err_tx_tiny: cas_tx_tiny_free(cp); - up(&cp->pm_sem); + mutex_unlock(&cp->pm_mutex); return err; } @@ -4382,7 +4383,7 @@ static int cas_close(struct net_device *dev) struct cas *cp = netdev_priv(dev); /* Make sure we don't get distracted by suspend/resume */ - down(&cp->pm_sem); + mutex_lock(&cp->pm_mutex); netif_stop_queue(dev); @@ -4399,7 +4400,7 @@ static int cas_close(struct net_device *dev) cas_spare_free(cp); cas_free_rxds(cp); cas_tx_tiny_free(cp); - up(&cp->pm_sem); + mutex_unlock(&cp->pm_mutex); return 0; } @@ -4834,10 +4835,10 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) unsigned long flags; int rc = -EOPNOTSUPP; - /* Hold the PM semaphore while doing ioctl's or we may collide + /* Hold the PM mutex while doing ioctl's or we may collide * with open/close and power management and oops. */ - down(&cp->pm_sem); + mutex_lock(&cp->pm_mutex); switch (cmd) { case SIOCGMIIPHY: /* Get address of MII PHY in use. */ data->phy_id = cp->phy_addr; @@ -4867,7 +4868,7 @@ static int cas_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) break; }; - up(&cp->pm_sem); + mutex_unlock(&cp->pm_mutex); return rc; } @@ -4994,7 +4995,7 @@ static int __devinit cas_init_one(struct pci_dev *pdev, spin_lock_init(&cp->tx_lock[i]); } spin_lock_init(&cp->stat_lock[N_TX_RINGS]); - init_MUTEX(&cp->pm_sem); + mutex_init(&cp->pm_mutex); init_timer(&cp->link_timer); cp->link_timer.function = cas_link_timer; @@ -5116,10 +5117,10 @@ err_out_free_consistent: cp->init_block, cp->block_dvma); err_out_iounmap: - down(&cp->pm_sem); + mutex_lock(&cp->pm_mutex); if (cp->hw_running) cas_shutdown(cp); - up(&cp->pm_sem); + mutex_unlock(&cp->pm_mutex); iounmap(cp->regs); @@ -5152,11 +5153,11 @@ static void __devexit cas_remove_one(struct pci_dev *pdev) cp = netdev_priv(dev); unregister_netdev(dev); - down(&cp->pm_sem); + mutex_lock(&cp->pm_mutex); flush_scheduled_work(); if (cp->hw_running) cas_shutdown(cp); - up(&cp->pm_sem); + mutex_unlock(&cp->pm_mutex); #if 1 if (cp->orig_cacheline_size) { @@ -5183,10 +5184,7 @@ static int cas_suspend(struct pci_dev *pdev, pm_message_t state) struct cas *cp = netdev_priv(dev); unsigned long flags; - /* We hold the PM semaphore during entire driver - * sleep time - */ - down(&cp->pm_sem); + mutex_lock(&cp->pm_mutex); /* If the driver is opened, we stop the DMA */ if (cp->opened) { @@ -5206,6 +5204,7 @@ static int cas_suspend(struct pci_dev *pdev, pm_message_t state) if (cp->hw_running) cas_shutdown(cp); + mutex_unlock(&cp->pm_mutex); return 0; } @@ -5217,6 +5216,7 @@ static int cas_resume(struct pci_dev *pdev) printk(KERN_INFO "%s: resuming\n", dev->name); + mutex_lock(&cp->pm_mutex); cas_hard_reset(cp); if (cp->opened) { unsigned long flags; @@ -5229,7 +5229,7 @@ static int cas_resume(struct pci_dev *pdev) netif_device_attach(dev); } - up(&cp->pm_sem); + mutex_unlock(&cp->pm_mutex); return 0; } #endif /* CONFIG_PM */ diff --git a/drivers/net/cassini.h b/drivers/net/cassini.h index 88063ef16cf..ab55c7ee101 100644 --- a/drivers/net/cassini.h +++ b/drivers/net/cassini.h @@ -4284,7 +4284,7 @@ struct cas { * (ie. not power managed) */ int hw_running; int opened; - struct semaphore pm_sem; /* open/close/suspend/resume */ + struct mutex pm_mutex; /* open/close/suspend/resume */ struct cas_init_block *init_block; struct cas_tx_desc *init_txds[MAX_TX_RINGS]; -- cgit v1.2.3 From e3968fc0f3db58e4c448ec20f66ce6da49d9bc5f Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 20 Mar 2006 22:34:25 -0800 Subject: [SUNGEM]: sem2mutex Semaphore to mutexes conversion. The conversion was generated via scripts, and the result was validated automatically via a script as well. Signed-off-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/sungem.c | 37 +++++++++++++++++++------------------ drivers/net/sungem.h | 6 +++--- 2 files changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index 28ce47a0240..38cd30cb7c7 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -2284,7 +2285,7 @@ static void gem_reset_task(void *data) { struct gem *gp = (struct gem *) data; - down(&gp->pm_sem); + mutex_lock(&gp->pm_mutex); netif_poll_disable(gp->dev); @@ -2311,7 +2312,7 @@ static void gem_reset_task(void *data) netif_poll_enable(gp->dev); - up(&gp->pm_sem); + mutex_unlock(&gp->pm_mutex); } @@ -2320,14 +2321,14 @@ static int gem_open(struct net_device *dev) struct gem *gp = dev->priv; int rc = 0; - down(&gp->pm_sem); + mutex_lock(&gp->pm_mutex); /* We need the cell enabled */ if (!gp->asleep) rc = gem_do_start(dev); gp->opened = (rc == 0); - up(&gp->pm_sem); + mutex_unlock(&gp->pm_mutex); return rc; } @@ -2340,13 +2341,13 @@ static int gem_close(struct net_device *dev) * our caller (dev_close) already did it for us */ - down(&gp->pm_sem); + mutex_lock(&gp->pm_mutex); gp->opened = 0; if (!gp->asleep) gem_do_stop(dev, 0); - up(&gp->pm_sem); + mutex_unlock(&gp->pm_mutex); return 0; } @@ -2358,7 +2359,7 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state) struct gem *gp = dev->priv; unsigned long flags; - down(&gp->pm_sem); + mutex_lock(&gp->pm_mutex); netif_poll_disable(dev); @@ -2391,11 +2392,11 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state) /* Stop the link timer */ del_timer_sync(&gp->link_timer); - /* Now we release the semaphore to not block the reset task who + /* Now we release the mutex to not block the reset task who * can take it too. We are marked asleep, so there will be no * conflict here */ - up(&gp->pm_sem); + mutex_unlock(&gp->pm_mutex); /* Wait for a pending reset task to complete */ while (gp->reset_task_pending) @@ -2424,7 +2425,7 @@ static int gem_resume(struct pci_dev *pdev) printk(KERN_INFO "%s: resuming\n", dev->name); - down(&gp->pm_sem); + mutex_lock(&gp->pm_mutex); /* Keep the cell enabled during the entire operation, no need to * take a lock here tho since nothing else can happen while we are @@ -2440,7 +2441,7 @@ static int gem_resume(struct pci_dev *pdev) * still asleep, a new sleep cycle may bring it back */ gem_put_cell(gp); - up(&gp->pm_sem); + mutex_unlock(&gp->pm_mutex); return 0; } pci_set_master(gp->pdev); @@ -2486,7 +2487,7 @@ static int gem_resume(struct pci_dev *pdev) netif_poll_enable(dev); - up(&gp->pm_sem); + mutex_unlock(&gp->pm_mutex); return 0; } @@ -2591,7 +2592,7 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu) return 0; } - down(&gp->pm_sem); + mutex_lock(&gp->pm_mutex); spin_lock_irq(&gp->lock); spin_lock(&gp->tx_lock); dev->mtu = new_mtu; @@ -2602,7 +2603,7 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu) } spin_unlock(&gp->tx_lock); spin_unlock_irq(&gp->lock); - up(&gp->pm_sem); + mutex_unlock(&gp->pm_mutex); return 0; } @@ -2771,10 +2772,10 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) int rc = -EOPNOTSUPP; unsigned long flags; - /* Hold the PM semaphore while doing ioctl's or we may collide + /* Hold the PM mutex while doing ioctl's or we may collide * with power management. */ - down(&gp->pm_sem); + mutex_lock(&gp->pm_mutex); spin_lock_irqsave(&gp->lock, flags); gem_get_cell(gp); @@ -2812,7 +2813,7 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) gem_put_cell(gp); spin_unlock_irqrestore(&gp->lock, flags); - up(&gp->pm_sem); + mutex_unlock(&gp->pm_mutex); return rc; } @@ -3033,7 +3034,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, spin_lock_init(&gp->lock); spin_lock_init(&gp->tx_lock); - init_MUTEX(&gp->pm_sem); + mutex_init(&gp->pm_mutex); init_timer(&gp->link_timer); gp->link_timer.function = gem_link_timer; diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h index 13006d759ad..89847215d00 100644 --- a/drivers/net/sungem.h +++ b/drivers/net/sungem.h @@ -980,15 +980,15 @@ struct gem { int tx_new, tx_old; unsigned int has_wol : 1; /* chip supports wake-on-lan */ - unsigned int asleep : 1; /* chip asleep, protected by pm_sem */ + unsigned int asleep : 1; /* chip asleep, protected by pm_mutex */ unsigned int asleep_wol : 1; /* was asleep with WOL enabled */ - unsigned int opened : 1; /* driver opened, protected by pm_sem */ + unsigned int opened : 1; /* driver opened, protected by pm_mutex */ unsigned int running : 1; /* chip running, protected by lock */ /* cell enable count, protected by lock */ int cell_enabled; - struct semaphore pm_sem; + struct mutex pm_mutex; u32 msg_enable; u32 status; -- cgit v1.2.3 From 471a24c0589cd192dcd2c6770ab6252cd42b1cff Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Mon, 20 Mar 2006 22:34:52 -0800 Subject: [WAN]: fix section mismatch warning in sbni In latest -mm sbni gives following warning: WARNING: drivers/net/wan/sbni.o - Section mismatch: reference to \ .init.data: from .text between 'init_module' (at offset 0x14ef) and \ 'cleanup_module' The warning is caused by init_module() calling a function declared __init. Declare init_module() __init too to fix warning. Signed-off-by: Sam Ravnborg Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/wan/sbni.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index db2c798ba89..175ba13bce4 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -1495,8 +1495,7 @@ module_param(skip_pci_probe, bool, 0); MODULE_LICENSE("GPL"); -int -init_module( void ) +int __init init_module( void ) { struct net_device *dev; int err; -- cgit v1.2.3 From 59f1741e541bf4f6139599389610a70de49c3ad2 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Mon, 20 Mar 2006 22:39:21 -0800 Subject: [TG3]: netif_carrier_off runs too early; could still be queued when init fails Move the netif_carrier_off() call from tg3_init_one()-> tg3_init_link_config() to tg3_open() as is the convention for most other network drivers. I was getting a panic after a tg3 device failed to initialize due to DMA failure. The oops pointed to the link watch queue with spinlock debugging enabled. Without spinlock debugging, the Oops didn't occur. I suspect that the link event was getting queued but not executed until after the DMA test had failed and the device was freed. The link event was then operating on freed memory, which could contain anything. With this patch applied, the Oops no longer occurs. [ Based upon feedback from Michael Chan, we move netif_carrier_off() to the end of tg3_init_one() instead of moving it to tg3_open() -DaveM ] Signed-off-by: Jeff Mahoney Signed-off-by: Andrew Morton Signed-off-by: David S. Miller --- drivers/net/tg3.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e0691cf1645..5104efe8ebf 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10926,7 +10926,6 @@ static void __devinit tg3_init_link_config(struct tg3 *tp) tp->link_config.speed = SPEED_INVALID; tp->link_config.duplex = DUPLEX_INVALID; tp->link_config.autoneg = AUTONEG_ENABLE; - netif_carrier_off(tp->dev); tp->link_config.active_speed = SPEED_INVALID; tp->link_config.active_duplex = DUPLEX_INVALID; tp->link_config.phy_is_low_power = 0; @@ -11390,6 +11389,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, (pdev->dma_mask == DMA_32BIT_MASK) ? 32 : (((u64) pdev->dma_mask == DMA_40BIT_MASK) ? 40 : 64)); + netif_carrier_off(tp->dev); + return 0; err_out_iounmap: -- cgit v1.2.3 From cbb042f9e1292434e3cacb90e67d8d381aeac5a9 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Mon, 20 Mar 2006 22:43:56 -0800 Subject: [NET]: Replace skb_pull/skb_postpull_rcsum with skb_pull_rcsum We're now starting to have quite a number of places that do skb_pull followed immediately by an skb_postpull_rcsum. We can merge these two operations into one function with skb_pull_rcsum. This makes sense since most pull operations on receive skb's need to update the checksum. I've decided to make this out-of-line since it is fairly big and the fast path where hardware checksums are enabled need to call csum_partial anyway. Since this is a brand new function we get to add an extra check on the len argument. As it is most callers of skb_pull ignore its return value which essentially means that there is no check on the len argument. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- drivers/net/ppp_generic.c | 4 ++-- drivers/net/pppoe.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 0245e40b51a..f608c12e3e8 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -1691,8 +1691,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) || ppp->npmode[npi] != NPMODE_PASS) { kfree_skb(skb); } else { - skb_pull(skb, 2); /* chop off protocol */ - skb_postpull_rcsum(skb, skb->data - 2, 2); + /* chop off protocol */ + skb_pull_rcsum(skb, 2); skb->dev = ppp->dev; skb->protocol = htons(npindex_to_ethertype[npi]); skb->mac.raw = skb->data; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index 9369f811075..475dc930380 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -337,8 +337,7 @@ static int pppoe_rcv_core(struct sock *sk, struct sk_buff *skb) if (sk->sk_state & PPPOX_BOUND) { struct pppoe_hdr *ph = (struct pppoe_hdr *) skb->nh.raw; int len = ntohs(ph->length); - skb_pull(skb, sizeof(struct pppoe_hdr)); - skb_postpull_rcsum(skb, ph, sizeof(*ph)); + skb_pull_rcsum(skb, sizeof(struct pppoe_hdr)); if (pskb_trim_rcsum(skb, len)) goto abort_kfree; -- cgit v1.2.3 From 81789ef5c9a435fbf94224987efe6fbb97ffab09 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 20 Mar 2006 23:00:14 -0800 Subject: [TG3]: make drivers/net/tg3.c:tg3_request_irq() static This patch makes the needlessly global function tg3_request_irq() static. Signed-off-by: Adrian Bunk Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 5104efe8ebf..b1e8d0698fa 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6531,7 +6531,7 @@ static void tg3_timer(unsigned long __opaque) add_timer(&tp->timer); } -int tg3_request_irq(struct tg3 *tp) +static int tg3_request_irq(struct tg3 *tp) { irqreturn_t (*fn)(int, void *, struct pt_regs *); unsigned long flags; -- cgit v1.2.3 From 30ca3e376e82cc44488b1d377adfb10b5818548e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 20 Mar 2006 23:02:36 -0800 Subject: [TG3]: Don't mark tg3_test_registers() as returning const. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b1e8d0698fa..e03d1ae50c3 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8059,7 +8059,7 @@ static int tg3_test_link(struct tg3 *tp) } /* Only test the commonly used registers */ -static const int tg3_test_registers(struct tg3 *tp) +static int tg3_test_registers(struct tg3 *tp) { int i, is_5705; u32 offset, read_mask, write_mask, val, save_val, read_val; -- cgit v1.2.3 From 00a6cae288138ce0444ab6f48a81da12afe557aa Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 21 Mar 2006 10:56:59 -0800 Subject: [PATCH] skge: use NAPI for tx cleanup. Cleanup transmit buffers using NAPI. This allows the transmit routine to leave interrupts enabled, and that improves performance. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 99 ++++++++++++++++++++++++------------------------------ 1 file changed, 44 insertions(+), 55 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 25e028b7ce4..1a30d5401c4 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2307,16 +2307,13 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) int i; u32 control, len; u64 map; - unsigned long flags; skb = skb_padto(skb, ETH_ZLEN); if (!skb) return NETDEV_TX_OK; - local_irq_save(flags); if (!spin_trylock(&skge->tx_lock)) { /* Collision - tell upper layer to requeue */ - local_irq_restore(flags); return NETDEV_TX_LOCKED; } @@ -2327,7 +2324,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) printk(KERN_WARNING PFX "%s: ring full when queue awake!\n", dev->name); } - spin_unlock_irqrestore(&skge->tx_lock, flags); + spin_unlock(&skge->tx_lock); return NETDEV_TX_BUSY; } @@ -2403,7 +2400,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) } dev->trans_start = jiffies; - spin_unlock_irqrestore(&skge->tx_lock, flags); + spin_unlock(&skge->tx_lock); return NETDEV_TX_OK; } @@ -2416,7 +2413,7 @@ static inline void skge_tx_free(struct skge_hw *hw, struct skge_element *e) pci_unmap_addr(e, mapaddr), pci_unmap_len(e, maplen), PCI_DMA_TODEVICE); - dev_kfree_skb_any(e->skb); + dev_kfree_skb(e->skb); e->skb = NULL; } else { pci_unmap_page(hw->pdev, @@ -2430,15 +2427,14 @@ static void skge_tx_clean(struct skge_port *skge) { struct skge_ring *ring = &skge->tx_ring; struct skge_element *e; - unsigned long flags; - spin_lock_irqsave(&skge->tx_lock, flags); + spin_lock_bh(&skge->tx_lock); for (e = ring->to_clean; e != ring->to_use; e = e->next) { ++skge->tx_avail; skge_tx_free(skge->hw, e); } ring->to_clean = e; - spin_unlock_irqrestore(&skge->tx_lock, flags); + spin_unlock_bh(&skge->tx_lock); } static void skge_tx_timeout(struct net_device *dev) @@ -2663,6 +2659,37 @@ resubmit: return NULL; } +static void skge_tx_done(struct skge_port *skge) +{ + struct skge_ring *ring = &skge->tx_ring; + struct skge_element *e; + + spin_lock(&skge->tx_lock); + for (e = ring->to_clean; prefetch(e->next), e != ring->to_use; e = e->next) { + struct skge_tx_desc *td = e->desc; + u32 control; + + rmb(); + control = td->control; + if (control & BMU_OWN) + break; + + if (unlikely(netif_msg_tx_done(skge))) + printk(KERN_DEBUG PFX "%s: tx done slot %td status 0x%x\n", + skge->netdev->name, e - ring->start, td->status); + + skge_tx_free(skge->hw, e); + e->skb = NULL; + ++skge->tx_avail; + } + ring->to_clean = e; + skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); + + if (skge->tx_avail > MAX_SKB_FRAGS + 1) + netif_wake_queue(skge->netdev); + + spin_unlock(&skge->tx_lock); +} static int skge_poll(struct net_device *dev, int *budget) { @@ -2670,8 +2697,10 @@ static int skge_poll(struct net_device *dev, int *budget) struct skge_hw *hw = skge->hw; struct skge_ring *ring = &skge->rx_ring; struct skge_element *e; - unsigned int to_do = min(dev->quota, *budget); - unsigned int work_done = 0; + int to_do = min(dev->quota, *budget); + int work_done = 0; + + skge_tx_done(skge); for (e = ring->to_clean; prefetch(e->next), work_done < to_do; e = e->next) { struct skge_rx_desc *rd = e->desc; @@ -2714,40 +2743,6 @@ static int skge_poll(struct net_device *dev, int *budget) return 0; } -static inline void skge_tx_intr(struct net_device *dev) -{ - struct skge_port *skge = netdev_priv(dev); - struct skge_hw *hw = skge->hw; - struct skge_ring *ring = &skge->tx_ring; - struct skge_element *e; - - spin_lock(&skge->tx_lock); - for (e = ring->to_clean; prefetch(e->next), e != ring->to_use; e = e->next) { - struct skge_tx_desc *td = e->desc; - u32 control; - - rmb(); - control = td->control; - if (control & BMU_OWN) - break; - - if (unlikely(netif_msg_tx_done(skge))) - printk(KERN_DEBUG PFX "%s: tx done slot %td status 0x%x\n", - dev->name, e - ring->start, td->status); - - skge_tx_free(hw, e); - e->skb = NULL; - ++skge->tx_avail; - } - ring->to_clean = e; - skge_write8(hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); - - if (skge->tx_avail > MAX_SKB_FRAGS + 1) - netif_wake_queue(dev); - - spin_unlock(&skge->tx_lock); -} - /* Parity errors seem to happen when Genesis is connected to a switch * with no other ports present. Heartbeat error?? */ @@ -2884,24 +2879,18 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; spin_lock(&hw->hw_lock); - if (status & IS_R1_F) { + if (status & (IS_R1_F|IS_XA1_F)) { skge_write8(hw, Q_ADDR(Q_R1, Q_CSR), CSR_IRQ_CL_F); - hw->intr_mask &= ~IS_R1_F; + hw->intr_mask &= ~(IS_R1_F|IS_XA1_F); netif_rx_schedule(hw->dev[0]); } - if (status & IS_R2_F) { + if (status & (IS_R2_F|IS_XA2_F)) { skge_write8(hw, Q_ADDR(Q_R2, Q_CSR), CSR_IRQ_CL_F); - hw->intr_mask &= ~IS_R2_F; + hw->intr_mask &= ~(IS_R2_F|IS_XA2_F); netif_rx_schedule(hw->dev[1]); } - if (status & IS_XA1_F) - skge_tx_intr(hw->dev[0]); - - if (status & IS_XA2_F) - skge_tx_intr(hw->dev[1]); - if (status & IS_PA_TO_RX1) { struct skge_port *skge = netdev_priv(hw->dev[0]); ++skge->net_stats.rx_over_errors; -- cgit v1.2.3 From cfc3ed796eda2c41fb20986d831ed56c0474279d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 21 Mar 2006 10:57:00 -0800 Subject: [PATCH] skge: use auto masking of irqs Improve performance of skge driver by not touching irq mask register as much. Since the interrupt source auto-masks, the driver can just leave it disabled until the end of the soft irq. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 54 +++++++++++++++++++++--------------------------------- drivers/net/skge.h | 1 - 2 files changed, 21 insertions(+), 34 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 1a30d5401c4..4fc9333f074 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -104,7 +104,6 @@ static const int txqaddr[] = { Q_XA1, Q_XA2 }; static const int rxqaddr[] = { Q_R1, Q_R2 }; static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F }; static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F }; -static const u32 portirqmask[] = { IS_PORT_1, IS_PORT_2 }; static int skge_get_regs_len(struct net_device *dev) { @@ -2184,12 +2183,6 @@ static int skge_up(struct net_device *dev) skge->tx_avail = skge->tx_ring.count - 1; - /* Enable IRQ from port */ - spin_lock_irq(&hw->hw_lock); - hw->intr_mask |= portirqmask[port]; - skge_write32(hw, B0_IMSK, hw->intr_mask); - spin_unlock_irq(&hw->hw_lock); - /* Initialize MAC */ spin_lock_bh(&hw->phy_lock); if (hw->chip_id == CHIP_ID_GENESIS) @@ -2246,11 +2239,6 @@ static int skge_down(struct net_device *dev) else yukon_stop(skge); - spin_lock_irq(&hw->hw_lock); - hw->intr_mask &= ~portirqmask[skge->port]; - skge_write32(hw, B0_IMSK, hw->intr_mask); - spin_unlock_irq(&hw->hw_lock); - /* Stop transmitter */ skge_write8(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_STOP); skge_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL), @@ -2734,11 +2722,9 @@ static int skge_poll(struct net_device *dev, int *budget) if (work_done >= to_do) return 1; /* not done */ - spin_lock_irq(&hw->hw_lock); - __netif_rx_complete(dev); - hw->intr_mask |= portirqmask[skge->port]; + netif_rx_complete(dev); + hw->intr_mask |= skge->port == 0 ? (IS_R1_F|IS_XA1_F) : (IS_R2_F|IS_XA2_F); skge_write32(hw, B0_IMSK, hw->intr_mask); - spin_unlock_irq(&hw->hw_lock); return 0; } @@ -2850,12 +2836,11 @@ static void skge_extirq(unsigned long data) int port; spin_lock(&hw->phy_lock); - for (port = 0; port < 2; port++) { + for (port = 0; port < hw->ports; port++) { struct net_device *dev = hw->dev[port]; + struct skge_port *skge = netdev_priv(dev); - if (dev && netif_running(dev)) { - struct skge_port *skge = netdev_priv(dev); - + if (netif_running(dev)) { if (hw->chip_id != CHIP_ID_GENESIS) yukon_phy_intr(skge); else @@ -2864,21 +2849,25 @@ static void skge_extirq(unsigned long data) } spin_unlock(&hw->phy_lock); - spin_lock_irq(&hw->hw_lock); hw->intr_mask |= IS_EXT_REG; skge_write32(hw, B0_IMSK, hw->intr_mask); - spin_unlock_irq(&hw->hw_lock); } static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) { struct skge_hw *hw = dev_id; - u32 status = skge_read32(hw, B0_SP_ISRC); + u32 status; - if (status == 0 || status == ~0) /* hotplug or shared irq */ + /* Reading this register masks IRQ */ + status = skge_read32(hw, B0_SP_ISRC); + if (status == 0) return IRQ_NONE; - spin_lock(&hw->hw_lock); + if (status & IS_EXT_REG) { + hw->intr_mask &= ~IS_EXT_REG; + tasklet_schedule(&hw->ext_tasklet); + } + if (status & (IS_R1_F|IS_XA1_F)) { skge_write8(hw, Q_ADDR(Q_R1, Q_CSR), CSR_IRQ_CL_F); hw->intr_mask &= ~(IS_R1_F|IS_XA1_F); @@ -2891,6 +2880,9 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) netif_rx_schedule(hw->dev[1]); } + if (likely((status & hw->intr_mask) == 0)) + return IRQ_HANDLED; + if (status & IS_PA_TO_RX1) { struct skge_port *skge = netdev_priv(hw->dev[0]); ++skge->net_stats.rx_over_errors; @@ -2918,13 +2910,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs) if (status & IS_HW_ERR) skge_error_irq(hw); - if (status & IS_EXT_REG) { - hw->intr_mask &= ~IS_EXT_REG; - tasklet_schedule(&hw->ext_tasklet); - } - skge_write32(hw, B0_IMSK, hw->intr_mask); - spin_unlock(&hw->hw_lock); return IRQ_HANDLED; } @@ -3070,7 +3056,10 @@ static int skge_reset(struct skge_hw *hw) else hw->ram_size = t8 * 4096; - hw->intr_mask = IS_HW_ERR | IS_EXT_REG; + hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1; + if (hw->ports > 1) + hw->intr_mask |= IS_PORT_2; + if (hw->chip_id == CHIP_ID_GENESIS) genesis_init(hw); else { @@ -3293,7 +3282,6 @@ static int __devinit skge_probe(struct pci_dev *pdev, hw->pdev = pdev; spin_lock_init(&hw->phy_lock); - spin_lock_init(&hw->hw_lock); tasklet_init(&hw->ext_tasklet, skge_extirq, (unsigned long) hw); hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 941f12a333b..2efdacc290e 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2402,7 +2402,6 @@ struct skge_hw { struct tasklet_struct ext_tasklet; spinlock_t phy_lock; - spinlock_t hw_lock; }; enum { -- cgit v1.2.3 From c3da14474063e71686039d961d14785a9c2971ae Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 21 Mar 2006 10:57:01 -0800 Subject: [PATCH] skge: check the allocation of ring buffer The SysKonnect Genesis and Yukon chip sets have restrictions on the possible control block area. The memory needs to not cross 4 Gig boundary, and it needs to be 8 byte aligned. This patch checks and fails to bring the device up if region is unacceptable. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 4fc9333f074..deca5066a44 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -727,7 +727,7 @@ static struct ethtool_ops skge_ethtool_ops = { * Allocate ring elements and chain them together * One-to-one association of board descriptors with ring elements */ -static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base) +static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u32 base) { struct skge_tx_desc *d; struct skge_element *e; @@ -2168,6 +2168,14 @@ static int skge_up(struct net_device *dev) if (!skge->mem) return -ENOMEM; + BUG_ON(skge->dma & 7); + + if ((u64)skge->dma >> 32 != ((u64) skge->dma + skge->mem_size) >> 32) { + printk(KERN_ERR PFX "pci_alloc_consistent region crosses 4G boundary\n"); + err = -EINVAL; + goto free_pci_mem; + } + memset(skge->mem, 0, skge->mem_size); if ((err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma))) -- cgit v1.2.3 From 93aea718c69d44ee492f233929686b15b5b3702d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 21 Mar 2006 10:57:02 -0800 Subject: [PATCH] skge: dma configuration cleanup Cleanup of the part of the code that sets up DMA configuration. Should cause no real change in operation, just clearer. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index deca5066a44..381669cc415 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -3251,22 +3251,18 @@ static int __devinit skge_probe(struct pci_dev *pdev, pci_set_master(pdev); - if (sizeof(dma_addr_t) > sizeof(u32) && - !(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) { + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { using_dac = 1; err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); - if (err < 0) { - printk(KERN_ERR PFX "%s unable to obtain 64 bit DMA " - "for consistent allocations\n", pci_name(pdev)); - goto err_out_free_regions; - } - } else { - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); - if (err) { - printk(KERN_ERR PFX "%s no usable DMA configuration\n", - pci_name(pdev)); - goto err_out_free_regions; - } + } else if (!(err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) { + using_dac = 0; + err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + } + + if (err) { + printk(KERN_ERR PFX "%s no usable DMA configuration\n", + pci_name(pdev)); + goto err_out_free_regions; } #ifdef __BIG_ENDIAN -- cgit v1.2.3 From ff7907aede7962629c2eb50e08b870316c80518f Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 21 Mar 2006 10:57:03 -0800 Subject: [PATCH] skge: use kcalloc Use kcalloc when allocating ring data structure. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 381669cc415..5ece10034df 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -733,13 +733,12 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u32 base) struct skge_element *e; int i; - ring->start = kmalloc(sizeof(*e)*ring->count, GFP_KERNEL); + ring->start = kcalloc(sizeof(*e), ring->count, GFP_KERNEL); if (!ring->start) return -ENOMEM; for (i = 0, e = ring->start, d = vaddr; i < ring->count; i++, e++, d++) { e->desc = d; - e->skb = NULL; if (i == ring->count - 1) { e->next = ring->start; d->next_offset = base; -- cgit v1.2.3 From c68ce71a340ffb5c589db5d9f9af1ce4ef81baa9 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 21 Mar 2006 10:57:04 -0800 Subject: [PATCH] skge: use mmiowb Add mmio barriers at the appropriate places, don't have a platform that needs them, but this is where the documentation of the patch says to add them. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 5ece10034df..8c674cdecd7 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2394,9 +2394,11 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - dev->trans_start = jiffies; + mmiowb(); spin_unlock(&skge->tx_lock); + dev->trans_start = jiffies; + return NETDEV_TX_OK; } @@ -2730,6 +2732,8 @@ static int skge_poll(struct net_device *dev, int *budget) return 1; /* not done */ netif_rx_complete(dev); + mmiowb(); + hw->intr_mask |= skge->port == 0 ? (IS_R1_F|IS_XA1_F) : (IS_R2_F|IS_XA2_F); skge_write32(hw, B0_IMSK, hw->intr_mask); -- cgit v1.2.3 From 203babb650d0c99a8be08f479d4a05d420988d89 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 21 Mar 2006 10:57:05 -0800 Subject: [PATCH] skge: formmating and whitespace cleanup Reformat some code to make it easier to read. And whitespace fixes. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 8c674cdecd7..7f8e8dd0fc6 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2177,15 +2177,17 @@ static int skge_up(struct net_device *dev) memset(skge->mem, 0, skge->mem_size); - if ((err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma))) + err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma); + if (err) goto free_pci_mem; err = skge_rx_fill(skge); if (err) goto free_rx_ring; - if ((err = skge_ring_alloc(&skge->tx_ring, skge->mem + rx_size, - skge->dma + rx_size))) + err = skge_ring_alloc(&skge->tx_ring, skge->mem + rx_size, + skge->dma + rx_size); + if (err) goto free_rx_ring; skge->tx_avail = skge->tx_ring.count - 1; @@ -2308,9 +2310,9 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; if (!spin_trylock(&skge->tx_lock)) { - /* Collision - tell upper layer to requeue */ - return NETDEV_TX_LOCKED; - } + /* Collision - tell upper layer to requeue */ + return NETDEV_TX_LOCKED; + } if (unlikely(skge->tx_avail < skb_shinfo(skb)->nr_frags +1)) { if (!netif_queue_stopped(dev)) { @@ -2709,8 +2711,8 @@ static int skge_poll(struct net_device *dev, int *budget) if (control & BMU_OWN) break; - skb = skge_rx_get(skge, e, control, rd->status, - le16_to_cpu(rd->csum2)); + skb = skge_rx_get(skge, e, control, rd->status, + le16_to_cpu(rd->csum2)); if (likely(skb)) { dev->last_rx = jiffies; netif_receive_skb(skb); @@ -3240,13 +3242,15 @@ static int __devinit skge_probe(struct pci_dev *pdev, struct skge_hw *hw; int err, using_dac = 0; - if ((err = pci_enable_device(pdev))) { + err = pci_enable_device(pdev); + if (err) { printk(KERN_ERR PFX "%s cannot enable PCI device\n", pci_name(pdev)); goto err_out; } - if ((err = pci_request_regions(pdev, DRV_NAME))) { + err = pci_request_regions(pdev, DRV_NAME); + if (err) { printk(KERN_ERR PFX "%s cannot obtain PCI resources\n", pci_name(pdev)); goto err_out_disable_pdev; @@ -3298,7 +3302,8 @@ static int __devinit skge_probe(struct pci_dev *pdev, goto err_out_free_hw; } - if ((err = request_irq(pdev->irq, skge_intr, SA_SHIRQ, DRV_NAME, hw))) { + err = request_irq(pdev->irq, skge_intr, SA_SHIRQ, DRV_NAME, hw); + if (err) { printk(KERN_ERR PFX "%s: cannot assign irq %d\n", pci_name(pdev), pdev->irq); goto err_out_iounmap; @@ -3316,7 +3321,8 @@ static int __devinit skge_probe(struct pci_dev *pdev, if ((dev = skge_devinit(hw, 0, using_dac)) == NULL) goto err_out_led_off; - if ((err = register_netdev(dev))) { + err = register_netdev(dev); + if (err) { printk(KERN_ERR PFX "%s: cannot register net device\n", pci_name(pdev)); goto err_out_free_netdev; -- cgit v1.2.3 From b9d64acc82c104df9e4d6b74cbb1af05a77b5d44 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 21 Mar 2006 10:57:06 -0800 Subject: [PATCH] skge: handle pci errors better When a PCI error occurs, try and report more info. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 7f8e8dd0fc6..0325fbceb35 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2764,17 +2764,6 @@ static void skge_mac_parity(struct skge_hw *hw, int port) ? GMF_CLI_TX_FC : GMF_CLI_TX_PE); } -static void skge_pci_clear(struct skge_hw *hw) -{ - u16 status; - - pci_read_config_word(hw->pdev, PCI_STATUS, &status); - skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); - pci_write_config_word(hw->pdev, PCI_STATUS, - status | PCI_STATUS_ERROR_BITS); - skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); -} - static void skge_mac_intr(struct skge_hw *hw, int port) { if (hw->chip_id == CHIP_ID_GENESIS) @@ -2816,23 +2805,39 @@ static void skge_error_irq(struct skge_hw *hw) if (hwstatus & IS_M2_PAR_ERR) skge_mac_parity(hw, 1); - if (hwstatus & IS_R1_PAR_ERR) + if (hwstatus & IS_R1_PAR_ERR) { + printk(KERN_ERR PFX "%s: receive queue parity error\n", + hw->dev[0]->name); skge_write32(hw, B0_R1_CSR, CSR_IRQ_CL_P); + } - if (hwstatus & IS_R2_PAR_ERR) + if (hwstatus & IS_R2_PAR_ERR) { + printk(KERN_ERR PFX "%s: receive queue parity error\n", + hw->dev[1]->name); skge_write32(hw, B0_R2_CSR, CSR_IRQ_CL_P); + } if (hwstatus & (IS_IRQ_MST_ERR|IS_IRQ_STAT)) { - printk(KERN_ERR PFX "hardware error detected (status 0x%x)\n", - hwstatus); + u16 pci_status, pci_cmd; + + pci_read_config_word(hw->pdev, PCI_COMMAND, &pci_cmd); + pci_read_config_word(hw->pdev, PCI_STATUS, &pci_status); - skge_pci_clear(hw); + printk(KERN_ERR PFX "%s: PCI error cmd=%#x status=%#x\n", + pci_name(hw->pdev), pci_cmd, pci_status); + + /* Write the error bits back to clear them. */ + pci_status &= PCI_STATUS_ERROR_BITS; + skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); + pci_write_config_word(hw->pdev, PCI_COMMAND, + pci_cmd | PCI_COMMAND_SERR | PCI_COMMAND_PARITY); + pci_write_config_word(hw->pdev, PCI_STATUS, pci_status); + skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); /* if error still set then just ignore it */ hwstatus = skge_read32(hw, B0_HWE_ISRC); if (hwstatus & IS_IRQ_STAT) { - pr_debug("IRQ status %x: still set ignoring hardware errors\n", - hwstatus); + printk(KERN_INFO PFX "unable to clear error (so ignoring them)\n"); hw->intr_mask &= ~IS_HW_ERR; } } @@ -2998,7 +3003,7 @@ static const char *skge_board_name(const struct skge_hw *hw) static int skge_reset(struct skge_hw *hw) { u32 reg; - u16 ctst; + u16 ctst, pci_status; u8 t8, mac_cfg, pmd_type, phy_type; int i; @@ -3009,8 +3014,13 @@ static int skge_reset(struct skge_hw *hw) skge_write8(hw, B0_CTST, CS_RST_CLR); /* clear PCI errors, if any */ - skge_pci_clear(hw); + skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON); + skge_write8(hw, B2_TST_CTRL2, 0); + pci_read_config_word(hw->pdev, PCI_STATUS, &pci_status); + pci_write_config_word(hw->pdev, PCI_STATUS, + pci_status | PCI_STATUS_ERROR_BITS); + skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF); skge_write8(hw, B0_CTST, CS_MRST_CLR); /* restore CLK_RUN bits (for Yukon-Lite) */ @@ -3377,7 +3387,6 @@ static void __devexit skge_remove(struct pci_dev *pdev) skge_write32(hw, B0_IMSK, 0); skge_write16(hw, B0_LED, LED_STAT_OFF); - skge_pci_clear(hw); skge_write8(hw, B0_CTST, CS_RST_SET); tasklet_kill(&hw->ext_tasklet); -- cgit v1.2.3 From 9362860fd1d9062ff9b3dca42aa3e1e68c2ddb67 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Tue, 21 Mar 2006 10:57:07 -0800 Subject: [PATCH] skge: version 1.4 Update version number Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 0325fbceb35..4eda81d41b1 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -44,7 +44,7 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "1.3" +#define DRV_VERSION "1.4" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 -- cgit v1.2.3 From 6f059c3e9042bc4eaa4f7a8dd651bbed9be144f2 Mon Sep 17 00:00:00 2001 From: Dale Farnsworth Date: Tue, 21 Mar 2006 11:44:35 -0700 Subject: [PATCH] mv643xx_eth: Cache align skb->data if CONFIG_NOT_COHERENT_CACHE When I/O is non-cache-coherent, we need to ensure that the I/O buffers we use don't share cache lines with other data. Signed-off-by: Dale Farnsworth Signed-off-by: Jeff Garzik --- drivers/net/mv643xx_eth.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index 7754d1974b9..4262c1da6d4 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h @@ -42,13 +42,23 @@ #define MAX_DESCS_PER_SKB 1 #endif +/* + * The MV643XX HW requires 8-byte alignment. However, when I/O + * is non-cache-coherent, we need to ensure that the I/O buffers + * we use don't share cache lines with other data. + */ +#if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_NOT_COHERENT_CACHE) +#define ETH_DMA_ALIGN L1_CACHE_BYTES +#else +#define ETH_DMA_ALIGN 8 +#endif + #define ETH_VLAN_HLEN 4 #define ETH_FCS_LEN 4 -#define ETH_DMA_ALIGN 8 /* hw requires 8-byte alignment */ -#define ETH_HW_IP_ALIGN 2 /* hw aligns IP header */ +#define ETH_HW_IP_ALIGN 2 /* hw aligns IP header */ #define ETH_WRAPPER_LEN (ETH_HW_IP_ALIGN + ETH_HLEN + \ - ETH_VLAN_HLEN + ETH_FCS_LEN) -#define ETH_RX_SKB_SIZE ((dev->mtu + ETH_WRAPPER_LEN + 7) & ~0x7) + ETH_VLAN_HLEN + ETH_FCS_LEN) +#define ETH_RX_SKB_SIZE (dev->mtu + ETH_WRAPPER_LEN + ETH_DMA_ALIGN) #define ETH_RX_QUEUES_ENABLED (1 << 0) /* use only Q0 for receive */ #define ETH_TX_QUEUES_ENABLED (1 << 0) /* use only Q0 for transmit */ -- cgit v1.2.3 From 290d4de5b71f60bb5853a7ef9f0e8c817cd26892 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 20 Mar 2006 15:48:15 -0800 Subject: [PATCH] sky2: remove support for untested Yukon EC/rev 0 The Yukon EC/rev0 (A1) chipset requires a bunch of workarounds. I copied these from sk98lin. But since they never got tested and add more cruft to the code; any attempt at using driver as is on this version will probably fail. It looks like this was a early engineering sample chip revision, if it ever shows up on a real system. Produce an error message. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 93 +++++++++++++++++++----------------------------------- drivers/net/sky2.h | 2 -- 2 files changed, 32 insertions(+), 63 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 73260364cba..3086e52032a 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -61,10 +61,6 @@ * a receive requires one (or two if using 64 bit dma). */ -#define is_ec_a1(hw) \ - unlikely((hw)->chip_id == CHIP_ID_YUKON_EC && \ - (hw)->chip_rev == CHIP_REV_YU_EC_A1) - #define RX_LE_SIZE 512 #define RX_LE_BYTES (RX_LE_SIZE*sizeof(struct sky2_rx_le)) #define RX_MAX_PENDING (RX_LE_SIZE/2 - 2) @@ -725,37 +721,11 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2) return le; } -/* - * This is a workaround code taken from SysKonnect sk98lin driver - * to deal with chip bug on Yukon EC rev 0 in the wraparound case. - */ -static void sky2_put_idx(struct sky2_hw *hw, unsigned q, - u16 idx, u16 *last, u16 size) +/* Update chip's next pointer */ +static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx) { wmb(); - if (is_ec_a1(hw) && idx < *last) { - u16 hwget = sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_GET_IDX)); - - if (hwget == 0) { - /* Start prefetching again */ - sky2_write8(hw, Y2_QADDR(q, PREF_UNIT_FIFO_WM), 0xe0); - goto setnew; - } - - if (hwget == size - 1) { - /* set watermark to one list element */ - sky2_write8(hw, Y2_QADDR(q, PREF_UNIT_FIFO_WM), 8); - - /* set put index to first list element */ - sky2_write16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX), 0); - } else /* have hardware go to end of list */ - sky2_write16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX), - size - 1); - } else { -setnew: - sky2_write16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX), idx); - } - *last = idx; + sky2_write16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX), idx); mmiowb(); } @@ -1001,7 +971,6 @@ static int sky2_rx_start(struct sky2_port *sky2) /* Tell chip about available buffers */ sky2_write16(hw, Y2_QADDR(rxq, PREF_UNIT_PUT_IDX), sky2->rx_put); - sky2->rx_last_put = sky2_read16(hw, Y2_QADDR(rxq, PREF_UNIT_PUT_IDX)); return 0; nomem: sky2_rx_clean(sky2); @@ -1299,8 +1268,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) netif_stop_queue(dev); } - sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod, - &sky2->tx_last_put, TX_RING_SIZE); + sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod); out_unlock: spin_unlock(&sky2->tx_lock); @@ -1843,8 +1811,7 @@ resubmit: sky2_rx_add(sky2, re->mapaddr); /* Tell receiver about new buffers. */ - sky2_put_idx(sky2->hw, rxqaddr[sky2->port], sky2->rx_put, - &sky2->rx_last_put, RX_LE_SIZE); + sky2_put_idx(sky2->hw, rxqaddr[sky2->port], sky2->rx_put); return skb; @@ -2238,6 +2205,23 @@ static int sky2_reset(struct sky2_hw *hw) return -EOPNOTSUPP; } + hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4; + + /* This rev is really old, and requires untested workarounds */ + if (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == CHIP_REV_YU_EC_A1) { + printk(KERN_ERR PFX "%s: unsupported revision Yukon-%s (0x%x) rev %d\n", + pci_name(hw->pdev), yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL], + hw->chip_id, hw->chip_rev); + return -EOPNOTSUPP; + } + + /* This chip is new and not tested yet */ + if (hw->chip_id == CHIP_ID_YUKON_EC_U) { + pr_info(PFX "%s: is a version of Yukon 2 chipset that has not been tested yet.\n", + pci_name(hw->pdev)); + pr_info("Please report success/failure to maintainer \n"); + } + /* disable ASF */ if (hw->chip_id <= CHIP_ID_YUKON_EC) { sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET); @@ -2271,7 +2255,6 @@ static int sky2_reset(struct sky2_hw *hw) if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC)) ++hw->ports; } - hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4; sky2_set_power_state(hw, PCI_D0); @@ -2338,29 +2321,17 @@ static int sky2_reset(struct sky2_hw *hw) sky2_write16(hw, STAT_LAST_IDX, STATUS_RING_SIZE - 1); /* These status setup values are copied from SysKonnect's driver */ - if (is_ec_a1(hw)) { - /* WA for dev. #4.3 */ - sky2_write16(hw, STAT_TX_IDX_TH, 0xfff); /* Tx Threshold */ + sky2_write16(hw, STAT_TX_IDX_TH, 10); + sky2_write8(hw, STAT_FIFO_WM, 16); - /* set Status-FIFO watermark */ - sky2_write8(hw, STAT_FIFO_WM, 0x21); /* WA for dev. #4.18 */ - - /* set Status-FIFO ISR watermark */ - sky2_write8(hw, STAT_FIFO_ISR_WM, 0x07); /* WA for dev. #4.18 */ - sky2_write32(hw, STAT_TX_TIMER_INI, sky2_us2clk(hw, 10000)); - } else { - sky2_write16(hw, STAT_TX_IDX_TH, 10); - sky2_write8(hw, STAT_FIFO_WM, 16); - - /* set Status-FIFO ISR watermark */ - if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev == 0) - sky2_write8(hw, STAT_FIFO_ISR_WM, 4); - else - sky2_write8(hw, STAT_FIFO_ISR_WM, 16); + /* set Status-FIFO ISR watermark */ + if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev == 0) + sky2_write8(hw, STAT_FIFO_ISR_WM, 4); + else + sky2_write8(hw, STAT_FIFO_ISR_WM, 16); - sky2_write32(hw, STAT_TX_TIMER_INI, sky2_us2clk(hw, 1000)); - sky2_write32(hw, STAT_ISR_TIMER_INI, sky2_us2clk(hw, 7)); - } + sky2_write32(hw, STAT_TX_TIMER_INI, sky2_us2clk(hw, 1000)); + sky2_write32(hw, STAT_ISR_TIMER_INI, sky2_us2clk(hw, 7)); /* enable status unit */ sky2_write32(hw, STAT_CTRL, SC_STAT_OP_ON); @@ -3091,7 +3062,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, INIT_WORK(&sky2->phy_task, sky2_phy_task, sky2); init_MUTEX(&sky2->phy_sema); sky2->tx_pending = TX_DEF_PENDING; - sky2->rx_pending = is_ec_a1(hw) ? 8 : RX_DEF_PENDING; + sky2->rx_pending = RX_DEF_PENDING; sky2->rx_bufsize = sky2_buf_size(ETH_DATA_LEN); hw->dev[port] = dev; diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index dce955c76f3..e2bf1d37ed0 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1840,7 +1840,6 @@ struct sky2_port { u16 tx_prod; /* next le to use */ u32 tx_addr64; u16 tx_pending; - u16 tx_last_put; u16 tx_last_mss; struct ring_info *rx_ring ____cacheline_aligned_in_smp; @@ -1849,7 +1848,6 @@ struct sky2_port { u16 rx_next; /* next re to check */ u16 rx_put; /* next le index to use */ u16 rx_pending; - u16 rx_last_put; u16 rx_bufsize; #ifdef SKY2_VLAN_TAG_USED u16 rx_tag; -- cgit v1.2.3 From c4b1580e8ad1aab13e0d8b97c7af3eebab8791ae Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 20 Mar 2006 15:48:16 -0800 Subject: [PATCH] sky2: drop broken wake on lan support Remove wake on lan support for now. It doesn't work right, and I don't have a machine with working suspend/resume to test or fix it. It will be re-enabled later. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 36 ------------------------------------ drivers/net/sky2.h | 1 - 2 files changed, 37 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3086e52032a..3a6c796eb70 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2777,38 +2777,6 @@ static int sky2_set_pauseparam(struct net_device *dev, return err; } -#ifdef CONFIG_PM -static void sky2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - struct sky2_port *sky2 = netdev_priv(dev); - - wol->supported = WAKE_MAGIC; - wol->wolopts = sky2->wol ? WAKE_MAGIC : 0; -} - -static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) -{ - struct sky2_port *sky2 = netdev_priv(dev); - struct sky2_hw *hw = sky2->hw; - - if (wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) - return -EOPNOTSUPP; - - sky2->wol = wol->wolopts == WAKE_MAGIC; - - if (sky2->wol) { - memcpy_toio(hw->regs + WOL_MAC_ADDR, dev->dev_addr, ETH_ALEN); - - sky2_write16(hw, WOL_CTRL_STAT, - WOL_CTL_ENA_PME_ON_MAGIC_PKT | - WOL_CTL_ENA_MAGIC_PKT_UNIT); - } else - sky2_write16(hw, WOL_CTRL_STAT, WOL_CTL_DEFAULT); - - return 0; -} -#endif - static int sky2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ecmd) { @@ -2996,10 +2964,6 @@ static struct ethtool_ops sky2_ethtool_ops = { .set_ringparam = sky2_set_ringparam, .get_pauseparam = sky2_get_pauseparam, .set_pauseparam = sky2_set_pauseparam, -#ifdef CONFIG_PM - .get_wol = sky2_get_wol, - .set_wol = sky2_set_wol, -#endif .phys_id = sky2_phys_id, .get_stats_count = sky2_get_stats_count, .get_ethtool_stats = sky2_get_ethtool_stats, diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index e2bf1d37ed0..2a23f3ad6d9 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1863,7 +1863,6 @@ struct sky2_port { u8 rx_pause; u8 tx_pause; u8 rx_csum; - u8 wol; struct net_device_stats net_stats; -- cgit v1.2.3 From e07b1aa8b3ebedd3c7e0e1b4b524f1b2d62707cf Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 20 Mar 2006 15:48:17 -0800 Subject: [PATCH] sky2: rework of NAPI and IRQ management Redo the interupt handling of sky2 driver based on the IRQ mangement documentation. All interrupts are handled by the device0 NAPI poll routine. Don't need to adjust interrupt mask in IRQ context, done only when changing device under RTNL. Therefore don't need hwlock anymore. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 276 +++++++++++++++++++++-------------------------------- drivers/net/sky2.h | 15 +-- 2 files changed, 111 insertions(+), 180 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3a6c796eb70..41dbe588de3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -500,9 +500,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) /* Force a renegotiation */ static void sky2_phy_reinit(struct sky2_port *sky2) { - down(&sky2->phy_sema); + spin_lock_bh(&sky2->phy_lock); sky2_phy_init(sky2->hw, sky2->port); - up(&sky2->phy_sema); + spin_unlock_bh(&sky2->phy_lock); } static void sky2_mac_init(struct sky2_hw *hw, unsigned port) @@ -567,9 +567,9 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC)); - down(&sky2->phy_sema); + spin_lock_bh(&sky2->phy_lock); sky2_phy_init(hw, port); - up(&sky2->phy_sema); + spin_unlock_bh(&sky2->phy_lock); /* MIB clear */ reg = gma_read16(hw, port, GM_PHY_ADDR); @@ -856,9 +856,9 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCGMIIREG: { u16 val = 0; - down(&sky2->phy_sema); + spin_lock_bh(&sky2->phy_lock); err = __gm_phy_read(hw, sky2->port, data->reg_num & 0x1f, &val); - up(&sky2->phy_sema); + spin_unlock_bh(&sky2->phy_lock); data->val_out = val; break; @@ -868,10 +868,10 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!capable(CAP_NET_ADMIN)) return -EPERM; - down(&sky2->phy_sema); + spin_lock_bh(&sky2->phy_lock); err = gm_phy_write(hw, sky2->port, data->reg_num & 0x1f, data->val_in); - up(&sky2->phy_sema); + spin_unlock_bh(&sky2->phy_lock); break; } return err; @@ -983,7 +983,7 @@ static int sky2_up(struct net_device *dev) struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; - u32 ramsize, rxspace; + u32 ramsize, rxspace, imask; int err = -ENOMEM; if (netif_msg_ifup(sky2)) @@ -1048,10 +1048,10 @@ static int sky2_up(struct net_device *dev) goto err_out; /* Enable interrupts from phy/mac for port */ - spin_lock_irq(&hw->hw_lock); - hw->intr_mask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2; - sky2_write32(hw, B0_IMSK, hw->intr_mask); - spin_unlock_irq(&hw->hw_lock); + imask = sky2_read32(hw, B0_IMSK); + imask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2; + sky2_write32(hw, B0_IMSK, imask); + return 0; err_out: @@ -1343,6 +1343,7 @@ static int sky2_down(struct net_device *dev) struct sky2_hw *hw = sky2->hw; unsigned port = sky2->port; u16 ctrl; + u32 imask; /* Never really got started! */ if (!sky2->tx_le) @@ -1354,14 +1355,6 @@ static int sky2_down(struct net_device *dev) /* Stop more packets from being queued */ netif_stop_queue(dev); - /* Disable port IRQ */ - spin_lock_irq(&hw->hw_lock); - hw->intr_mask &= ~((sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2); - sky2_write32(hw, B0_IMSK, hw->intr_mask); - spin_unlock_irq(&hw->hw_lock); - - flush_scheduled_work(); - sky2_phy_reset(hw, port); /* Stop transmitter */ @@ -1405,6 +1398,11 @@ static int sky2_down(struct net_device *dev) sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); + /* Disable port IRQ */ + imask = sky2_read32(hw, B0_IMSK); + imask &= ~(sky2->port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2; + sky2_write32(hw, B0_IMSK, imask); + /* turn off LED's */ sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); @@ -1599,20 +1597,19 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) return 0; } -/* - * Interrupt from PHY are handled outside of interrupt context - * because accessing phy registers requires spin wait which might - * cause excess interrupt latency. - */ -static void sky2_phy_task(void *arg) +/* Interrupt from PHY */ +static void sky2_phy_intr(struct sky2_hw *hw, unsigned port) { - struct sky2_port *sky2 = arg; - struct sky2_hw *hw = sky2->hw; + struct net_device *dev = hw->dev[port]; + struct sky2_port *sky2 = netdev_priv(dev); u16 istatus, phystat; - down(&sky2->phy_sema); - istatus = gm_phy_read(hw, sky2->port, PHY_MARV_INT_STAT); - phystat = gm_phy_read(hw, sky2->port, PHY_MARV_PHY_STAT); + spin_lock(&sky2->phy_lock); + istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT); + phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT); + + if (!netif_running(dev)) + goto out; if (netif_msg_intr(sky2)) printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n", @@ -1638,12 +1635,7 @@ static void sky2_phy_task(void *arg) sky2_link_down(sky2); } out: - up(&sky2->phy_sema); - - spin_lock_irq(&hw->hw_lock); - hw->intr_mask |= (sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2; - sky2_write32(hw, B0_IMSK, hw->intr_mask); - spin_unlock_irq(&hw->hw_lock); + spin_unlock(&sky2->phy_lock); } @@ -1655,20 +1647,6 @@ static void sky2_tx_timeout(struct net_device *dev) struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; unsigned txq = txqaddr[sky2->port]; - u16 ridx; - - /* Maybe we just missed an status interrupt */ - spin_lock(&sky2->tx_lock); - ridx = sky2_read16(hw, - sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX); - sky2_tx_complete(sky2, ridx); - spin_unlock(&sky2->tx_lock); - - if (!netif_queue_stopped(dev)) { - if (net_ratelimit()) - pr_info(PFX "transmit interrupt missed? recovered\n"); - return; - } if (netif_msg_timer(sky2)) printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); @@ -1698,6 +1676,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) struct sky2_hw *hw = sky2->hw; int err; u16 ctl, mode; + u32 imask; if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) return -EINVAL; @@ -1710,12 +1689,15 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) return 0; } + imask = sky2_read32(hw, B0_IMSK); sky2_write32(hw, B0_IMSK, 0); dev->trans_start = jiffies; /* prevent tx timeout */ netif_stop_queue(dev); netif_poll_disable(hw->dev[0]); + synchronize_irq(hw->pdev->irq); + ctl = gma_read16(hw, sky2->port, GM_GP_CTRL); gma_write16(hw, sky2->port, GM_GP_CTRL, ctl & ~GM_GPCR_RX_ENA); sky2_rx_stop(sky2); @@ -1734,7 +1716,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) sky2_write8(hw, RB_ADDR(rxqaddr[sky2->port], RB_CTRL), RB_ENA_OP_MD); err = sky2_rx_start(sky2); - sky2_write32(hw, B0_IMSK, hw->intr_mask); + sky2_write32(hw, B0_IMSK, imask); if (err) dev_close(dev); @@ -1838,76 +1820,51 @@ error: goto resubmit; } -/* - * Check for transmit complete - */ -#define TX_NO_STATUS 0xffff - -static void sky2_tx_check(struct sky2_hw *hw, int port, u16 last) +/* Transmit complete */ +static inline void sky2_tx_done(struct net_device *dev, u16 last) { - if (last != TX_NO_STATUS) { - struct net_device *dev = hw->dev[port]; - if (dev && netif_running(dev)) { - struct sky2_port *sky2 = netdev_priv(dev); + struct sky2_port *sky2 = netdev_priv(dev); - spin_lock(&sky2->tx_lock); - sky2_tx_complete(sky2, last); - spin_unlock(&sky2->tx_lock); - } + if (netif_running(dev)) { + spin_lock(&sky2->tx_lock); + sky2_tx_complete(sky2, last); + spin_unlock(&sky2->tx_lock); } } -/* - * Both ports share the same status interrupt, therefore there is only - * one poll routine. - */ -static int sky2_poll(struct net_device *dev0, int *budget) +/* Process status response ring */ +static int sky2_status_intr(struct sky2_hw *hw, int to_do) { - struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw; - unsigned int to_do = min(dev0->quota, *budget); - unsigned int work_done = 0; - u16 hwidx; - u16 tx_done[2] = { TX_NO_STATUS, TX_NO_STATUS }; - - sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); - - /* - * Kick the STAT_LEV_TIMER_CTRL timer. - * This fixes my hangs on Yukon-EC (0xb6) rev 1. - * The if clause is there to start the timer only if it has been - * configured correctly and not been disabled via ethtool. - */ - if (sky2_read8(hw, STAT_LEV_TIMER_CTRL) == TIM_START) { - sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_STOP); - sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START); - } + int work_done = 0; - hwidx = sky2_read16(hw, STAT_PUT_IDX); - BUG_ON(hwidx >= STATUS_RING_SIZE); rmb(); - while (hwidx != hw->st_idx) { + for(;;) { struct sky2_status_le *le = hw->st_le + hw->st_idx; struct net_device *dev; struct sky2_port *sky2; struct sk_buff *skb; u32 status; u16 length; + u8 link, opcode; + + opcode = le->opcode; + if (!opcode) + break; + opcode &= ~HW_OWNER; - le = hw->st_le + hw->st_idx; hw->st_idx = (hw->st_idx + 1) % STATUS_RING_SIZE; - prefetch(hw->st_le + hw->st_idx); + le->opcode = 0; - BUG_ON(le->link >= 2); - dev = hw->dev[le->link]; - if (dev == NULL || !netif_running(dev)) - continue; + link = le->link; + BUG_ON(link >= 2); + dev = hw->dev[link]; sky2 = netdev_priv(dev); - status = le32_to_cpu(le->status); - length = le16_to_cpu(le->length); + length = le->length; + status = le->status; - switch (le->opcode & ~HW_OWNER) { + switch (opcode) { case OP_RXSTAT: skb = sky2_receive(sky2, length, status); if (!skb) @@ -1947,42 +1904,23 @@ static int sky2_poll(struct net_device *dev0, int *budget) case OP_TXINDEXLE: /* TX index reports status for both ports */ - tx_done[0] = status & 0xffff; - tx_done[1] = ((status >> 24) & 0xff) - | (u16)(length & 0xf) << 8; + sky2_tx_done(hw->dev[0], status & 0xffff); + if (hw->dev[1]) + sky2_tx_done(hw->dev[1], + ((status >> 24) & 0xff) + | (u16)(length & 0xf) << 8); break; default: if (net_ratelimit()) printk(KERN_WARNING PFX - "unknown status opcode 0x%x\n", le->opcode); + "unknown status opcode 0x%x\n", opcode); break; } } exit_loop: - sky2_tx_check(hw, 0, tx_done[0]); - sky2_tx_check(hw, 1, tx_done[1]); - - if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) { - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); - } - - if (likely(work_done < to_do)) { - spin_lock_irq(&hw->hw_lock); - __netif_rx_complete(dev0); - - hw->intr_mask |= Y2_IS_STAT_BMU; - sky2_write32(hw, B0_IMSK, hw->intr_mask); - spin_unlock_irq(&hw->hw_lock); - - return 0; - } else { - *budget -= work_done; - dev0->quota -= work_done; - return 1; - } + return work_done; } static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status) @@ -2101,42 +2039,17 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port) } } -static void sky2_phy_intr(struct sky2_hw *hw, unsigned port) -{ - struct net_device *dev = hw->dev[port]; - struct sky2_port *sky2 = netdev_priv(dev); - - hw->intr_mask &= ~(port == 0 ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2); - sky2_write32(hw, B0_IMSK, hw->intr_mask); - - schedule_work(&sky2->phy_task); -} -static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) +static int sky2_poll(struct net_device *dev0, int *budget) { - struct sky2_hw *hw = dev_id; - struct net_device *dev0 = hw->dev[0]; - u32 status; - - status = sky2_read32(hw, B0_Y2_SP_ISRC2); - if (status == 0 || status == ~0) - return IRQ_NONE; + struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw; + int work_limit = min(dev0->quota, *budget); + int work_done = 0; + u32 status = sky2_read32(hw, B0_ISRC); - spin_lock(&hw->hw_lock); if (status & Y2_IS_HW_ERR) sky2_hw_intr(hw); - /* Do NAPI for Rx and Tx status */ - if (status & Y2_IS_STAT_BMU) { - hw->intr_mask &= ~Y2_IS_STAT_BMU; - sky2_write32(hw, B0_IMSK, hw->intr_mask); - - if (likely(__netif_rx_schedule_prep(dev0))) { - prefetch(&hw->st_le[hw->st_idx]); - __netif_rx_schedule(dev0); - } - } - if (status & Y2_IS_IRQ_PHY1) sky2_phy_intr(hw, 0); @@ -2149,9 +2062,38 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) if (status & Y2_IS_IRQ_MAC2) sky2_mac_intr(hw, 1); + if (status & Y2_IS_STAT_BMU) { + work_done = sky2_status_intr(hw, work_limit); + *budget -= work_done; + dev0->quota -= work_done; + + if (work_done >= work_limit) + return 1; + + sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ); + } + + netif_rx_complete(dev0); + + /* Ack interrupt and re-enable */ sky2_write32(hw, B0_Y2_SP_ICR, 2); + return 0; +} + +static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sky2_hw *hw = dev_id; + struct net_device *dev0 = hw->dev[0]; + u32 status; + + /* Reading this mask interrupts as side effect */ + status = sky2_read32(hw, B0_Y2_SP_ISRC2); + if (status == 0 || status == ~0) + return IRQ_NONE; - spin_unlock(&hw->hw_lock); + prefetch(&hw->st_le[hw->st_idx]); + if (likely(__netif_rx_schedule_prep(dev0))) + __netif_rx_schedule(dev0); return IRQ_HANDLED; } @@ -2320,7 +2262,6 @@ static int sky2_reset(struct sky2_hw *hw) /* Set the list last index */ sky2_write16(hw, STAT_LAST_IDX, STATUS_RING_SIZE - 1); - /* These status setup values are copied from SysKonnect's driver */ sky2_write16(hw, STAT_TX_IDX_TH, 10); sky2_write8(hw, STAT_FIFO_WM, 16); @@ -2714,7 +2655,7 @@ static int sky2_phys_id(struct net_device *dev, u32 data) ms = data * 1000; /* save initial values */ - down(&sky2->phy_sema); + spin_lock_bh(&sky2->phy_lock); if (hw->chip_id == CHIP_ID_YUKON_XL) { u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); @@ -2730,9 +2671,9 @@ static int sky2_phys_id(struct net_device *dev, u32 data) sky2_led(hw, port, onoff); onoff = !onoff; - up(&sky2->phy_sema); + spin_unlock_bh(&sky2->phy_lock); interrupted = msleep_interruptible(250); - down(&sky2->phy_sema); + spin_lock_bh(&sky2->phy_lock); ms -= 250; } @@ -2747,7 +2688,7 @@ static int sky2_phys_id(struct net_device *dev, u32 data) gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover); } - up(&sky2->phy_sema); + spin_unlock_bh(&sky2->phy_lock); return 0; } @@ -3023,8 +2964,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, */ sky2->rx_csum = (hw->chip_id != CHIP_ID_YUKON_XL); - INIT_WORK(&sky2->phy_task, sky2_phy_task, sky2); - init_MUTEX(&sky2->phy_sema); + spin_lock_init(&sky2->phy_lock); sky2->tx_pending = TX_DEF_PENDING; sky2->rx_pending = RX_DEF_PENDING; sky2->rx_bufsize = sky2_buf_size(ETH_DATA_LEN); @@ -3136,7 +3076,6 @@ static int __devinit sky2_probe(struct pci_dev *pdev, goto err_out_free_hw; } hw->pm_cap = pm_cap; - spin_lock_init(&hw->hw_lock); #ifdef __BIG_ENDIAN /* byte swap descriptors in hardware */ @@ -3196,8 +3135,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, goto err_out_unregister; } - hw->intr_mask = Y2_IS_BASE; - sky2_write32(hw, B0_IMSK, hw->intr_mask); + sky2_write32(hw, B0_IMSK, Y2_IS_BASE); pci_set_drvdata(pdev, hw); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 2a23f3ad6d9..db362b69b0b 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -278,13 +278,9 @@ enum { Y2_IS_CHK_TXS1 = 1<<1, /* Descriptor error TXS 1 */ Y2_IS_CHK_TXA1 = 1<<0, /* Descriptor error TXA 1 */ - Y2_IS_BASE = Y2_IS_HW_ERR | Y2_IS_STAT_BMU | - Y2_IS_POLL_CHK | Y2_IS_TWSI_RDY | - Y2_IS_IRQ_SW | Y2_IS_TIMINT, - Y2_IS_PORT_1 = Y2_IS_IRQ_PHY1 | Y2_IS_IRQ_MAC1 | - Y2_IS_CHK_RX1 | Y2_IS_CHK_TXA1 | Y2_IS_CHK_TXS1, - Y2_IS_PORT_2 = Y2_IS_IRQ_PHY2 | Y2_IS_IRQ_MAC2 | - Y2_IS_CHK_RX2 | Y2_IS_CHK_TXA2 | Y2_IS_CHK_TXS2, + Y2_IS_BASE = Y2_IS_HW_ERR | Y2_IS_STAT_BMU, + Y2_IS_PORT_1 = Y2_IS_IRQ_PHY1 | Y2_IS_IRQ_MAC1, + Y2_IS_PORT_2 = Y2_IS_IRQ_PHY2 | Y2_IS_IRQ_MAC2, }; /* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */ @@ -1832,6 +1828,7 @@ struct sky2_port { struct net_device *netdev; unsigned port; u32 msg_enable; + spinlock_t phy_lock; spinlock_t tx_lock ____cacheline_aligned_in_smp; struct tx_ring_info *tx_ring; @@ -1866,16 +1863,12 @@ struct sky2_port { struct net_device_stats net_stats; - struct work_struct phy_task; - struct semaphore phy_sema; }; struct sky2_hw { void __iomem *regs; struct pci_dev *pdev; struct net_device *dev[2]; - spinlock_t hw_lock; - u32 intr_mask; int pm_cap; u8 chip_id; -- cgit v1.2.3 From 77b3d6a2d56be5af87ffae5bb78a39c847d49f99 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 20 Mar 2006 15:48:18 -0800 Subject: [PATCH] sky2: coalescing parameters Change default coalescing parameters slightly, and allow wider range of values. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 41dbe588de3..7e3353f55c3 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2272,7 +2272,8 @@ static int sky2_reset(struct sky2_hw *hw) sky2_write8(hw, STAT_FIFO_ISR_WM, 16); sky2_write32(hw, STAT_TX_TIMER_INI, sky2_us2clk(hw, 1000)); - sky2_write32(hw, STAT_ISR_TIMER_INI, sky2_us2clk(hw, 7)); + sky2_write32(hw, STAT_ISR_TIMER_INI, sky2_us2clk(hw, 20)); + sky2_write32(hw, STAT_LEV_TIMER_INI, sky2_us2clk(hw, 100)); /* enable status unit */ sky2_write32(hw, STAT_CTRL, SC_STAT_OP_ON); @@ -2758,19 +2759,11 @@ static int sky2_set_coalesce(struct net_device *dev, { struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; - const u32 tmin = sky2_clk2us(hw, 1); - const u32 tmax = 5000; + const u32 tmax = sky2_clk2us(hw, 0x0ffffff); - if (ecmd->tx_coalesce_usecs != 0 && - (ecmd->tx_coalesce_usecs < tmin || ecmd->tx_coalesce_usecs > tmax)) - return -EINVAL; - - if (ecmd->rx_coalesce_usecs != 0 && - (ecmd->rx_coalesce_usecs < tmin || ecmd->rx_coalesce_usecs > tmax)) - return -EINVAL; - - if (ecmd->rx_coalesce_usecs_irq != 0 && - (ecmd->rx_coalesce_usecs_irq < tmin || ecmd->rx_coalesce_usecs_irq > tmax)) + if (ecmd->tx_coalesce_usecs > tmax || + ecmd->rx_coalesce_usecs > tmax || + ecmd->rx_coalesce_usecs_irq > tmax) return -EINVAL; if (ecmd->tx_max_coalesced_frames >= TX_RING_SIZE-1) -- cgit v1.2.3 From fb2690a9bfa330aff3de29cbdde526591ac90dce Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 20 Mar 2006 15:48:19 -0800 Subject: [PATCH] sky2: add MSI support Add MSI support to sky2 driver. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++--- drivers/net/sky2.h | 2 ++ 2 files changed, 79 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 7e3353f55c3..2e29972b8d0 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -92,6 +92,10 @@ static int copybreak __read_mostly = 256; module_param(copybreak, int, 0); MODULE_PARM_DESC(copybreak, "Receive copy threshold"); +static int disable_msi = 0; +module_param(disable_msi, int, 0); +MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); + static const struct pci_device_id sky2_id_table[] = { { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) }, { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, @@ -2045,7 +2049,7 @@ static int sky2_poll(struct net_device *dev0, int *budget) struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw; int work_limit = min(dev0->quota, *budget); int work_done = 0; - u32 status = sky2_read32(hw, B0_ISRC); + u32 status = sky2_read32(hw, B0_Y2_SP_EISR); if (status & Y2_IS_HW_ERR) sky2_hw_intr(hw); @@ -2075,8 +2079,7 @@ static int sky2_poll(struct net_device *dev0, int *budget) netif_rx_complete(dev0); - /* Ack interrupt and re-enable */ - sky2_write32(hw, B0_Y2_SP_ICR, 2); + status = sky2_read32(hw, B0_Y2_SP_LISR); return 0; } @@ -3001,6 +3004,66 @@ static void __devinit sky2_show_addr(struct net_device *dev) dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); } +/* Handle software interrupt used during MSI test */ +static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id, + struct pt_regs *regs) +{ + struct sky2_hw *hw = dev_id; + u32 status = sky2_read32(hw, B0_Y2_SP_ISRC2); + + if (status == 0) + return IRQ_NONE; + + if (status & Y2_IS_IRQ_SW) { + hw->msi_detected = 1; + wake_up(&hw->msi_wait); + sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ); + } + sky2_write32(hw, B0_Y2_SP_ICR, 2); + + return IRQ_HANDLED; +} + +/* Test interrupt path by forcing a a software IRQ */ +static int __devinit sky2_test_msi(struct sky2_hw *hw) +{ + struct pci_dev *pdev = hw->pdev; + int err; + + sky2_write32(hw, B0_IMSK, Y2_IS_IRQ_SW); + + err = request_irq(pdev->irq, sky2_test_intr, SA_SHIRQ, DRV_NAME, hw); + if (err) { + printk(KERN_ERR PFX "%s: cannot assign irq %d\n", + pci_name(pdev), pdev->irq); + return err; + } + + init_waitqueue_head (&hw->msi_wait); + + sky2_write8(hw, B0_CTST, CS_ST_SW_IRQ); + wmb(); + + wait_event_timeout(hw->msi_wait, hw->msi_detected, HZ/10); + + if (!hw->msi_detected) { + /* MSI test failed, go back to INTx mode */ + printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, " + "switching to INTx mode. Please report this failure to " + "the PCI maintainer and include system chipset information.\n", + pci_name(pdev)); + + err = -EOPNOTSUPP; + sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ); + } + + sky2_write32(hw, B0_IMSK, 0); + + free_irq(pdev->irq, hw); + + return err; +} + static int __devinit sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -3121,7 +3184,15 @@ static int __devinit sky2_probe(struct pci_dev *pdev, } } - err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ, DRV_NAME, hw); + if (!disable_msi && pci_enable_msi(pdev) == 0) { + err = sky2_test_msi(hw); + if (err == -EOPNOTSUPP) + pci_disable_msi(pdev); + else if (err) + goto err_out_unregister; + } + + err = request_irq(pdev->irq, sky2_intr, SA_SHIRQ, DRV_NAME, hw); if (err) { printk(KERN_ERR PFX "%s: cannot assign irq %d\n", pci_name(pdev), pdev->irq); @@ -3135,6 +3206,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, return 0; err_out_unregister: + pci_disable_msi(pdev); if (dev1) { unregister_netdev(dev1); free_netdev(dev1); @@ -3177,6 +3249,7 @@ static void __devexit sky2_remove(struct pci_dev *pdev) sky2_read8(hw, B0_CTST); free_irq(pdev->irq, hw); + pci_disable_msi(pdev); pci_free_consistent(pdev, STATUS_LE_BYTES, hw->st_le, hw->st_dma); pci_release_regions(pdev); pci_disable_device(pdev); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index db362b69b0b..50e9f7d38bf 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1879,6 +1879,8 @@ struct sky2_hw { struct sky2_status_le *st_le; u32 st_idx; dma_addr_t st_dma; + int msi_detected; + wait_queue_head_t msi_wait; }; /* Register accessor for memory mapped device */ -- cgit v1.2.3 From d89e1343959200a578465d50bb36c89733cf66a7 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 20 Mar 2006 15:48:20 -0800 Subject: [PATCH] sky2: whitespace fixes Small whitespace fixes. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 2e29972b8d0..ffe3aa7e2ab 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -852,7 +852,7 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!netif_running(dev)) return -ENODEV; /* Phy still in reset */ - switch(cmd) { + switch (cmd) { case SIOCGMIIPHY: data->phy_id = PHY_ADDR_MARV; @@ -1304,7 +1304,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) struct tx_ring_info *re = sky2->tx_ring + put; struct sk_buff *skb = re->skb; - nxt = re->idx; + nxt = re->idx; BUG_ON(nxt >= TX_RING_SIZE); prefetch(sky2->tx_ring + nxt); @@ -1320,7 +1320,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) struct tx_ring_info *fre; fre = sky2->tx_ring + (put + i + 1) % TX_RING_SIZE; pci_unmap_page(pdev, pci_unmap_addr(fre, mapaddr), - skb_shinfo(skb)->frags[i].size, + skb_shinfo(skb)->frags[i].size, PCI_DMA_TODEVICE); } @@ -2187,7 +2187,7 @@ static int sky2_reset(struct sky2_hw *hw) sky2_write8(hw, B0_CTST, CS_MRST_CLR); /* clear any PEX errors */ - if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP)) + if (pci_find_capability(hw->pdev, PCI_CAP_ID_EXP)) sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL); @@ -2954,7 +2954,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, sky2->speed = -1; sky2->advertising = sky2_supported_modes(hw); - /* Receive checksum disabled for Yukon XL + /* Receive checksum disabled for Yukon XL * because of observed problems with incorrect * values when multiple packets are received in one interrupt */ -- cgit v1.2.3 From 8f24664da64f8db094cd9d379b16fc1d8776d1df Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 20 Mar 2006 15:48:21 -0800 Subject: [PATCH] sky2: transmit recovery This patch decodes state and revovers from any races in the transmit timeout and NAPI logic. It should never trigger, but if it does then do the right thing. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index ffe3aa7e2ab..ab36a7460a2 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1328,7 +1328,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) } sky2->tx_cons = put; - if (netif_queue_stopped(dev) && tx_avail(sky2) > MAX_SKB_TX_LE) + if (tx_avail(sky2) > MAX_SKB_TX_LE) netif_wake_queue(dev); } @@ -1651,17 +1651,40 @@ static void sky2_tx_timeout(struct net_device *dev) struct sky2_port *sky2 = netdev_priv(dev); struct sky2_hw *hw = sky2->hw; unsigned txq = txqaddr[sky2->port]; + u16 report, done; if (netif_msg_timer(sky2)) printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); - sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP); - sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); + report = sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX); + done = sky2_read16(hw, Q_ADDR(txq, Q_DONE)); - sky2_tx_clean(sky2); + printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n", + dev->name, + sky2->tx_cons, sky2->tx_prod, report, done); + + if (report != done) { + printk(KERN_INFO PFX "status burst pending (irq moderation?)\n"); + + sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); + sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); + } else if (report != sky2->tx_cons) { + printk(KERN_INFO PFX "status report lost?\n"); - sky2_qset(hw, txq); - sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1); + spin_lock_bh(&sky2->tx_lock); + sky2_tx_complete(sky2, report); + spin_unlock_bh(&sky2->tx_lock); + } else { + printk(KERN_INFO PFX "hardware hung? flushing\n"); + + sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP); + sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET); + + sky2_tx_clean(sky2); + + sky2_qset(hw, txq); + sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1); + } } @@ -2097,6 +2120,8 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) prefetch(&hw->st_le[hw->st_idx]); if (likely(__netif_rx_schedule_prep(dev0))) __netif_rx_schedule(dev0); + else + printk(KERN_DEBUG PFX "irq race detected\n"); return IRQ_HANDLED; } -- cgit v1.2.3 From d257924e85a81561a956f1791fa5a226e3a32ce1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 20 Mar 2006 15:48:22 -0800 Subject: [PATCH] sky2: handle all error irqs The hardware has additional error trap interrupt bits. I have never seen them trigger, but if they do, it looks like this might be useful. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 55 ++++++++++++++++++++++++++++++++++++++++++++---------- drivers/net/sky2.h | 6 ++++-- 2 files changed, 49 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index ab36a7460a2..380bb59f351 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2066,6 +2066,27 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port) } } +/* This should never happen it is a fatal situation */ +static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port, + const char *rxtx, u32 mask) +{ + struct net_device *dev = hw->dev[port]; + struct sky2_port *sky2 = netdev_priv(dev); + u32 imask; + + printk(KERN_ERR PFX "%s: %s descriptor error (hardware problem)\n", + dev ? dev->name : "", rxtx); + + imask = sky2_read32(hw, B0_IMSK); + imask &= ~mask; + sky2_write32(hw, B0_IMSK, imask); + + if (dev) { + spin_lock(&sky2->phy_lock); + sky2_link_down(sky2); + spin_unlock(&sky2->phy_lock); + } +} static int sky2_poll(struct net_device *dev0, int *budget) { @@ -2074,20 +2095,34 @@ static int sky2_poll(struct net_device *dev0, int *budget) int work_done = 0; u32 status = sky2_read32(hw, B0_Y2_SP_EISR); - if (status & Y2_IS_HW_ERR) - sky2_hw_intr(hw); + if (unlikely(status & ~Y2_IS_STAT_BMU)) { + if (status & Y2_IS_HW_ERR) + sky2_hw_intr(hw); + + if (status & Y2_IS_IRQ_PHY1) + sky2_phy_intr(hw, 0); - if (status & Y2_IS_IRQ_PHY1) - sky2_phy_intr(hw, 0); + if (status & Y2_IS_IRQ_PHY2) + sky2_phy_intr(hw, 1); - if (status & Y2_IS_IRQ_PHY2) - sky2_phy_intr(hw, 1); + if (status & Y2_IS_IRQ_MAC1) + sky2_mac_intr(hw, 0); - if (status & Y2_IS_IRQ_MAC1) - sky2_mac_intr(hw, 0); + if (status & Y2_IS_IRQ_MAC2) + sky2_mac_intr(hw, 1); - if (status & Y2_IS_IRQ_MAC2) - sky2_mac_intr(hw, 1); + if (status & Y2_IS_CHK_RX1) + sky2_descriptor_error(hw, 0, "receive", Y2_IS_CHK_RX1); + + if (status & Y2_IS_CHK_RX2) + sky2_descriptor_error(hw, 1, "receive", Y2_IS_CHK_RX2); + + if (status & Y2_IS_CHK_TXA1) + sky2_descriptor_error(hw, 0, "transmit", Y2_IS_CHK_TXA1); + + if (status & Y2_IS_CHK_TXA2) + sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2); + } if (status & Y2_IS_STAT_BMU) { work_done = sky2_status_intr(hw, work_limit); diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 50e9f7d38bf..d63cd5a1b71 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -279,8 +279,10 @@ enum { Y2_IS_CHK_TXA1 = 1<<0, /* Descriptor error TXA 1 */ Y2_IS_BASE = Y2_IS_HW_ERR | Y2_IS_STAT_BMU, - Y2_IS_PORT_1 = Y2_IS_IRQ_PHY1 | Y2_IS_IRQ_MAC1, - Y2_IS_PORT_2 = Y2_IS_IRQ_PHY2 | Y2_IS_IRQ_MAC2, + Y2_IS_PORT_1 = Y2_IS_IRQ_PHY1 | Y2_IS_IRQ_MAC1 + | Y2_IS_CHK_TXA1 | Y2_IS_CHK_RX1, + Y2_IS_PORT_2 = Y2_IS_IRQ_PHY2 | Y2_IS_IRQ_MAC2 + | Y2_IS_CHK_TXA2 | Y2_IS_CHK_RX2, }; /* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */ -- cgit v1.2.3 From 8368f31c8f51ef8ba61ce9fff7b94259777b6419 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Mon, 20 Mar 2006 15:48:23 -0800 Subject: [PATCH] sky2 version 1.1 Set version to 1.1 Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 380bb59f351..f08fe6c884b 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -51,7 +51,7 @@ #include "sky2.h" #define DRV_NAME "sky2" -#define DRV_VERSION "0.15" +#define DRV_VERSION "1.1" #define PFX DRV_NAME " " /* -- cgit v1.2.3 From ac62ef043504d5c754357325cd514553ddabb046 Mon Sep 17 00:00:00 2001 From: Don Fry Date: Mon, 20 Mar 2006 15:26:03 -0800 Subject: [PATCH] pcnet32: support boards with multiple phys Boards with multiple PHYs were not being handled properly by the pcnet32 driver. This patch by Thomas Bogendoerfer with changes by me will allow Allied Telesyn 2700FTX and 2701FTX boards to use either the copper or the fiber interfaces. It has been tested on ia32 and ppc64 hardware. Philippe Seewer also tested and improved the patch. ethtool for pcnet32 already supports multiple phys. See also bugzilla bug 4219. Please apply to 2.6.16 Signed-off-by: Don Fry Signed-off-by: Jeff Garzik --- drivers/net/pcnet32.c | 236 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 212 insertions(+), 24 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 7e900572eaf..1bc3f5bffb9 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -22,8 +22,8 @@ *************************************************************************/ #define DRV_NAME "pcnet32" -#define DRV_VERSION "1.31c" -#define DRV_RELDATE "01.Nov.2005" +#define DRV_VERSION "1.32" +#define DRV_RELDATE "18.Mar.2006" #define PFX DRV_NAME ": " static const char * const version = @@ -133,7 +133,7 @@ static const char pcnet32_gstrings_test[][ETH_GSTRING_LEN] = { }; #define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN) -#define PCNET32_NUM_REGS 168 +#define PCNET32_NUM_REGS 136 #define MAX_UNITS 8 /* More are supported, limit only on options */ static int options[MAX_UNITS]; @@ -265,6 +265,9 @@ static int homepna[MAX_UNITS]; * v1.31c 01 Nov 2005 Don Fry Allied Telesyn 2700/2701 FX are 100Mbit only. * Force 100Mbit FD if Auto (ASEL) is selected. * See Bugzilla 2669 and 4551. + * v1.32 18 Mar2006 Thomas Bogendoerfer and Don Fry added Multi-Phy + * handling for supporting AT-270x FTX cards with FX and Tx PHYs. + * Philippe Seewer assisted with auto negotiation and testing. */ @@ -375,6 +378,7 @@ struct pcnet32_private { unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ struct net_device_stats stats; char tx_full; + char phycount; /* number of phys found */ int options; unsigned int shared_irq:1, /* shared irq possible */ dxsuflo:1, /* disable transmit stop on uflo */ @@ -384,6 +388,9 @@ struct pcnet32_private { struct timer_list watchdog_timer; struct timer_list blink_timer; u32 msg_enable; /* debug message level */ + + /* each bit indicates an available PHY */ + u32 phymask; }; static void pcnet32_probe_vlbus(void); @@ -415,6 +422,7 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, static void pcnet32_purge_tx_ring(struct net_device *dev); static int pcnet32_alloc_ring(struct net_device *dev, char *name); static void pcnet32_free_ring(struct net_device *dev); +static void pcnet32_check_media(struct net_device *dev, int verbose); enum pci_flags_bit { @@ -936,9 +944,14 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data) return 0; } +#define PCNET32_REGS_PER_PHY 32 +#define PCNET32_MAX_PHYS 32 static int pcnet32_get_regs_len(struct net_device *dev) { - return(PCNET32_NUM_REGS * sizeof(u16)); + struct pcnet32_private *lp = dev->priv; + int j = lp->phycount * PCNET32_REGS_PER_PHY; + + return((PCNET32_NUM_REGS + j) * sizeof(u16)); } static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, @@ -998,9 +1011,14 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, /* read mii phy registers */ if (lp->mii) { - for (i=0; i<32; i++) { - lp->a.write_bcr(ioaddr, 33, ((lp->mii_if.phy_id) << 5) | i); - *buff++ = lp->a.read_bcr(ioaddr, 34); + int j; + for (j=0; jphymask & (1 << j)) { + for (i=0; ia.write_bcr(ioaddr, 33, (j << 5) | i); + *buff++ = lp->a.read_bcr(ioaddr, 34); + } + } } } @@ -1009,10 +1027,6 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, a->write_csr(ioaddr, 5, 0x0000); } - i = buff - (u16 *)ptr; - for (; i < PCNET32_NUM_REGS; i++) - *buff++ = 0; - spin_unlock_irqrestore(&lp->lock, flags); } @@ -1185,7 +1199,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) if (cards_found < MAX_UNITS && homepna[cards_found]) media |= 1; /* switch to home wiring mode */ if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_DEBUG PFX "media set to %sMbit mode.\n", + printk(KERN_DEBUG PFX "media set to %sMbit mode.\n", (media & 1) ? "1" : "10"); a->write_bcr(ioaddr, 49, media); break; @@ -1401,8 +1415,34 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) } /* Set the mii phy_id so that we can query the link state */ - if (lp->mii) + if (lp->mii) { + /* lp->phycount and lp->phymask are set to 0 by memset above */ + lp->mii_if.phy_id = ((lp->a.read_bcr (ioaddr, 33)) >> 5) & 0x1f; + /* scan for PHYs */ + for (i=0; iphycount++; + lp->phymask |= (1 << i); + lp->mii_if.phy_id = i; + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(KERN_INFO PFX "Found PHY %04x:%04x at address %d.\n", + id1, id2, i); + } + lp->a.write_bcr(ioaddr, 33, (lp->mii_if.phy_id) << 5); + if (lp->phycount > 1) { + lp->options |= PCNET32_PORT_MII; + } + } init_timer (&lp->watchdog_timer); lp->watchdog_timer.data = (unsigned long) dev; @@ -1625,7 +1665,7 @@ pcnet32_open(struct net_device *dev) dev->name); } } - { + if (lp->phycount < 2) { /* * 24 Jun 2004 according AMD, in order to change the PHY, * DANAS (or DISPM for 79C976) must be set; then select the speed, @@ -1651,6 +1691,62 @@ pcnet32_open(struct net_device *dev) lp->a.write_bcr(ioaddr, 32, val); } } + } else { + int first_phy = -1; + u16 bmcr; + u32 bcr9; + struct ethtool_cmd ecmd; + + /* + * There is really no good other way to handle multiple PHYs + * other than turning off all automatics + */ + val = lp->a.read_bcr(ioaddr, 2); + lp->a.write_bcr(ioaddr, 2, val & ~2); + val = lp->a.read_bcr(ioaddr, 32); + lp->a.write_bcr(ioaddr, 32, val & ~(1 << 7)); /* stop MII manager */ + + if (!(lp->options & PCNET32_PORT_ASEL)) { + /* setup ecmd */ + ecmd.port = PORT_MII; + ecmd.transceiver = XCVR_INTERNAL; + ecmd.autoneg = AUTONEG_DISABLE; + ecmd.speed = lp->options & PCNET32_PORT_100 ? SPEED_100 : SPEED_10; + bcr9 = lp->a.read_bcr(ioaddr, 9); + + if (lp->options & PCNET32_PORT_FD) { + ecmd.duplex = DUPLEX_FULL; + bcr9 |= (1 << 0); + } else { + ecmd.duplex = DUPLEX_HALF; + bcr9 |= ~(1 << 0); + } + lp->a.write_bcr(ioaddr, 9, bcr9); + } + + for (i=0; iphymask & (1 << i)) { + /* isolate all but the first PHY */ + bmcr = mdio_read(dev, i, MII_BMCR); + if (first_phy == -1) { + first_phy = i; + mdio_write(dev, i, MII_BMCR, bmcr & ~BMCR_ISOLATE); + } else { + mdio_write(dev, i, MII_BMCR, bmcr | BMCR_ISOLATE); + } + /* use mii_ethtool_sset to setup PHY */ + lp->mii_if.phy_id = i; + ecmd.phy_address = i; + if (lp->options & PCNET32_PORT_ASEL) { + mii_ethtool_gset(&lp->mii_if, &ecmd); + ecmd.autoneg = AUTONEG_ENABLE; + } + mii_ethtool_sset(&lp->mii_if, &ecmd); + } + } + lp->mii_if.phy_id = first_phy; + if (netif_msg_link(lp)) + printk(KERN_INFO "%s: Using PHY number %d.\n", dev->name, first_phy); } #ifdef DO_DXSUFLO @@ -1680,11 +1776,9 @@ pcnet32_open(struct net_device *dev) netif_start_queue(dev); - /* If we have mii, print the link status and start the watchdog */ - if (lp->mii) { - mii_check_media (&lp->mii_if, netif_msg_link(lp), 1); - mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); - } + /* Print the link status and start the watchdog */ + pcnet32_check_media (dev, 1); + mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); i = 0; while (i++ < 100) @@ -2430,17 +2524,111 @@ static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return rc; } +static int pcnet32_check_otherphy(struct net_device *dev) +{ + struct pcnet32_private *lp = dev->priv; + struct mii_if_info mii = lp->mii_if; + u16 bmcr; + int i; + + for (i = 0; i < PCNET32_MAX_PHYS; i++) { + if (i == lp->mii_if.phy_id) + continue; /* skip active phy */ + if (lp->phymask & (1 << i)) { + mii.phy_id = i; + if (mii_link_ok(&mii)) { + /* found PHY with active link */ + if (netif_msg_link(lp)) + printk(KERN_INFO "%s: Using PHY number %d.\n", dev->name, i); + + /* isolate inactive phy */ + bmcr = mdio_read(dev, lp->mii_if.phy_id, MII_BMCR); + mdio_write(dev, lp->mii_if.phy_id, MII_BMCR, bmcr | BMCR_ISOLATE); + + /* de-isolate new phy */ + bmcr = mdio_read(dev, i, MII_BMCR); + mdio_write(dev, i, MII_BMCR, bmcr & ~BMCR_ISOLATE); + + /* set new phy address */ + lp->mii_if.phy_id = i; + return 1; + } + } + } + return 0; +} + +/* + * Show the status of the media. Similar to mii_check_media however it + * correctly shows the link speed for all (tested) pcnet32 variants. + * Devices with no mii just report link state without speed. + * + * Caller is assumed to hold and release the lp->lock. + */ + +static void pcnet32_check_media(struct net_device *dev, int verbose) +{ + struct pcnet32_private *lp = dev->priv; + int curr_link; + int prev_link = netif_carrier_ok(dev) ? 1 : 0; + u32 bcr9; + + if (lp->mii) { + curr_link = mii_link_ok(&lp->mii_if); + } else { + ulong ioaddr = dev->base_addr; /* card base I/O address */ + curr_link = (lp->a.read_bcr(ioaddr, 4) != 0xc0); + } + if (!curr_link) { + if (prev_link || verbose) { + netif_carrier_off(dev); + if (netif_msg_link(lp)) + printk(KERN_INFO "%s: link down\n", dev->name); + } + if (lp->phycount > 1) { + curr_link = pcnet32_check_otherphy(dev); + prev_link = 0; + } + } else if (verbose || !prev_link) { + netif_carrier_on(dev); + if (lp->mii) { + if (netif_msg_link(lp)) { + struct ethtool_cmd ecmd; + mii_ethtool_gset(&lp->mii_if, &ecmd); + printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n", + dev->name, + (ecmd.speed == SPEED_100) ? "100" : "10", + (ecmd.duplex == DUPLEX_FULL) ? "full" : "half"); + } + bcr9 = lp->a.read_bcr(dev->base_addr, 9); + if ((bcr9 & (1 << 0)) != lp->mii_if.full_duplex) { + if (lp->mii_if.full_duplex) + bcr9 |= (1 << 0); + else + bcr9 &= ~(1 << 0); + lp->a.write_bcr(dev->base_addr, 9, bcr9); + } + } else { + if (netif_msg_link(lp)) + printk(KERN_INFO "%s: link up\n", dev->name); + } + } +} + +/* + * Check for loss of link and link establishment. + * Can not use mii_check_media because it does nothing if mode is forced. + */ + static void pcnet32_watchdog(struct net_device *dev) { struct pcnet32_private *lp = dev->priv; unsigned long flags; /* Print the link status if it has changed */ - if (lp->mii) { - spin_lock_irqsave(&lp->lock, flags); - mii_check_media (&lp->mii_if, netif_msg_link(lp), 0); - spin_unlock_irqrestore(&lp->lock, flags); - } + spin_lock_irqsave(&lp->lock, flags); + pcnet32_check_media(dev, 0); + spin_unlock_irqrestore(&lp->lock, flags); mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); } -- cgit v1.2.3 From 09779c6df2dbe95483269d194b327d41fe2cc57e Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Mon, 20 Mar 2006 11:54:27 -0500 Subject: [PATCH] smc91x: allow for dynamic bus access configs All accessor's different methods are now selected with C code and unused ones statically optimized away at compile time instead of being selected with #if's and #ifdef's. This has many advantages such as allowing the compiler to validate the syntax of the whole code, making it cleaner and easier to understand, and ultimately allowing people to define configuration symbols in terms of variables if they really want to dynamically support multiple bus configurations at the same time (with the unavoidable performance cost). Signed-off-by: Nicolas Pitre Signed-off-by: Jeff Garzik --- drivers/net/smc91x.c | 53 +++--- drivers/net/smc91x.h | 474 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 307 insertions(+), 220 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 75e9b3b910c..0e9833adf9f 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -215,15 +215,12 @@ struct smc_local { spinlock_t lock; -#ifdef SMC_CAN_USE_DATACS - u32 __iomem *datacs; -#endif - #ifdef SMC_USE_PXA_DMA /* DMA needs the physical address of the chip */ u_long physaddr; #endif void __iomem *base; + void __iomem *datacs; }; #if SMC_DEBUG > 0 @@ -2104,9 +2101,8 @@ static int smc_enable_device(struct platform_device *pdev) * Set the appropriate byte/word mode. */ ecsr = readb(addr + (ECSR << SMC_IO_SHIFT)) & ~ECSR_IOIS8; -#ifndef SMC_CAN_USE_16BIT - ecsr |= ECSR_IOIS8; -#endif + if (!SMC_CAN_USE_16BIT) + ecsr |= ECSR_IOIS8; writeb(ecsr, addr + (ECSR << SMC_IO_SHIFT)); local_irq_restore(flags); @@ -2143,40 +2139,39 @@ static void smc_release_attrib(struct platform_device *pdev) release_mem_region(res->start, ATTRIB_SIZE); } -#ifdef SMC_CAN_USE_DATACS -static void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev) +static inline void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev) { - struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32"); - struct smc_local *lp = netdev_priv(ndev); + if (SMC_CAN_USE_DATACS) { + struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32"); + struct smc_local *lp = netdev_priv(ndev); - if (!res) - return; + if (!res) + return; - if(!request_mem_region(res->start, SMC_DATA_EXTENT, CARDNAME)) { - printk(KERN_INFO "%s: failed to request datacs memory region.\n", CARDNAME); - return; - } + if(!request_mem_region(res->start, SMC_DATA_EXTENT, CARDNAME)) { + printk(KERN_INFO "%s: failed to request datacs memory region.\n", CARDNAME); + return; + } - lp->datacs = ioremap(res->start, SMC_DATA_EXTENT); + lp->datacs = ioremap(res->start, SMC_DATA_EXTENT); + } } static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev) { - struct smc_local *lp = netdev_priv(ndev); - struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32"); + if (SMC_CAN_USE_DATACS) { + struct smc_local *lp = netdev_priv(ndev); + struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32"); - if (lp->datacs) - iounmap(lp->datacs); + if (lp->datacs) + iounmap(lp->datacs); - lp->datacs = NULL; + lp->datacs = NULL; - if (res) - release_mem_region(res->start, SMC_DATA_EXTENT); + if (res) + release_mem_region(res->start, SMC_DATA_EXTENT); + } } -#else -static void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev) {} -static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev) {} -#endif /* * smc_init(void) diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index e0efd1964e7..e1be1af5120 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -275,7 +275,10 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_insw(a,r,p,l) readsw ((void*) ((a) + (r)), p, l) #define SMC_outw(v,a,r) ({ writew ((v), (a) + (r)); LPD7A40X_IOBARRIER; }) -static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l) +#define SMC_outsw LPD7A40X_SMC_outsw + +static inline void LPD7A40X_SMC_outsw(unsigned long a, int r, + unsigned char* p, int l) { unsigned short* ps = (unsigned short*) p; while (l-- > 0) { @@ -342,10 +345,6 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l) #endif -#ifndef SMC_IRQ_FLAGS -#define SMC_IRQ_FLAGS SA_TRIGGER_RISING -#endif - #ifdef SMC_USE_PXA_DMA /* * Let's use the DMA engine on the XScale PXA2xx for RX packets. This is @@ -441,10 +440,85 @@ smc_pxa_dma_irq(int dma, void *dummy, struct pt_regs *regs) #endif /* SMC_USE_PXA_DMA */ -/* Because of bank switching, the LAN91x uses only 16 I/O ports */ +/* + * Everything a particular hardware setup needs should have been defined + * at this point. Add stubs for the undefined cases, mainly to avoid + * compilation warnings since they'll be optimized away, or to prevent buggy + * use of them. + */ + +#if ! SMC_CAN_USE_32BIT +#define SMC_inl(ioaddr, reg) ({ BUG(); 0; }) +#define SMC_outl(x, ioaddr, reg) BUG() +#define SMC_insl(a, r, p, l) BUG() +#define SMC_outsl(a, r, p, l) BUG() +#endif + +#if !defined(SMC_insl) || !defined(SMC_outsl) +#define SMC_insl(a, r, p, l) BUG() +#define SMC_outsl(a, r, p, l) BUG() +#endif + +#if ! SMC_CAN_USE_16BIT + +/* + * Any 16-bit access is performed with two 8-bit accesses if the hardware + * can't do it directly. Most registers are 16-bit so those are mandatory. + */ +#define SMC_outw(x, ioaddr, reg) \ + do { \ + unsigned int __val16 = (x); \ + SMC_outb( __val16, ioaddr, reg ); \ + SMC_outb( __val16 >> 8, ioaddr, reg + (1 << SMC_IO_SHIFT));\ + } while (0) +#define SMC_inw(ioaddr, reg) \ + ({ \ + unsigned int __val16; \ + __val16 = SMC_inb( ioaddr, reg ); \ + __val16 |= SMC_inb( ioaddr, reg + (1 << SMC_IO_SHIFT)) << 8; \ + __val16; \ + }) + +#define SMC_insw(a, r, p, l) BUG() +#define SMC_outsw(a, r, p, l) BUG() + +#endif + +#if !defined(SMC_insw) || !defined(SMC_outsw) +#define SMC_insw(a, r, p, l) BUG() +#define SMC_outsw(a, r, p, l) BUG() +#endif + +#if ! SMC_CAN_USE_8BIT +#define SMC_inb(ioaddr, reg) ({ BUG(); 0; }) +#define SMC_outb(x, ioaddr, reg) BUG() +#define SMC_insb(a, r, p, l) BUG() +#define SMC_outsb(a, r, p, l) BUG() +#endif + +#if !defined(SMC_insb) || !defined(SMC_outsb) +#define SMC_insb(a, r, p, l) BUG() +#define SMC_outsb(a, r, p, l) BUG() +#endif + +#ifndef SMC_CAN_USE_DATACS +#define SMC_CAN_USE_DATACS 0 +#endif + #ifndef SMC_IO_SHIFT #define SMC_IO_SHIFT 0 #endif + +#ifndef SMC_IRQ_FLAGS +#define SMC_IRQ_FLAGS SA_TRIGGER_RISING +#endif + +#ifndef SMC_INTERRUPT_PREAMBLE +#define SMC_INTERRUPT_PREAMBLE +#endif + + +/* Because of bank switching, the LAN91x uses only 16 I/O ports */ #define SMC_IO_EXTENT (16 << SMC_IO_SHIFT) #define SMC_DATA_EXTENT (4) @@ -817,6 +891,11 @@ static const char * chip_ids[ 16 ] = { * Note: the following macros do *not* select the bank -- this must * be done separately as needed in the main code. The SMC_REG() macro * only uses the bank argument for debugging purposes (when enabled). + * + * Note: despite inline functions being safer, everything leading to this + * should preferably be macros to let BUG() display the line number in + * the core source code since we're interested in the top call site + * not in any inline function location. */ #if SMC_DEBUG > 0 @@ -834,62 +913,142 @@ static const char * chip_ids[ 16 ] = { #define SMC_REG(reg, bank) (reg<> 8) -#define SMC_GET_TXFIFO() (SMC_inw( ioaddr, TXFIFO_REG ) & 0xFF) -#define SMC_GET_RXFIFO() (SMC_inw( ioaddr, TXFIFO_REG ) >> 8) -#define SMC_GET_INT() (SMC_inw( ioaddr, INT_REG ) & 0xFF) +/* + * Hack Alert: Some setups just can't write 8 or 16 bits reliably when not + * aligned to a 32 bit boundary. I tell you that does exist! + * Fortunately the affected register accesses can be easily worked around + * since we can write zeroes to the preceeding 16 bits without adverse + * effects and use a 32-bit access. + * + * Enforce it on any 32-bit capable setup for now. + */ +#define SMC_MUST_ALIGN_WRITE SMC_CAN_USE_32BIT + +#define SMC_GET_PN() \ + ( SMC_CAN_USE_8BIT ? (SMC_inb(ioaddr, PN_REG)) \ + : (SMC_inw(ioaddr, PN_REG) & 0xFF) ) + +#define SMC_SET_PN(x) \ + do { \ + if (SMC_MUST_ALIGN_WRITE) \ + SMC_outl((x)<<16, ioaddr, SMC_REG(0, 2)); \ + else if (SMC_CAN_USE_8BIT) \ + SMC_outb(x, ioaddr, PN_REG); \ + else \ + SMC_outw(x, ioaddr, PN_REG); \ + } while (0) + +#define SMC_GET_AR() \ + ( SMC_CAN_USE_8BIT ? (SMC_inb(ioaddr, AR_REG)) \ + : (SMC_inw(ioaddr, PN_REG) >> 8) ) + +#define SMC_GET_TXFIFO() \ + ( SMC_CAN_USE_8BIT ? (SMC_inb(ioaddr, TXFIFO_REG)) \ + : (SMC_inw(ioaddr, TXFIFO_REG) & 0xFF) ) + +#define SMC_GET_RXFIFO() \ + ( SMC_CAN_USE_8BIT ? (SMC_inb(ioaddr, RXFIFO_REG)) \ + : (SMC_inw(ioaddr, TXFIFO_REG) >> 8) ) + +#define SMC_GET_INT() \ + ( SMC_CAN_USE_8BIT ? (SMC_inb(ioaddr, INT_REG)) \ + : (SMC_inw(ioaddr, INT_REG) & 0xFF) ) + #define SMC_ACK_INT(x) \ do { \ - unsigned long __flags; \ - int __mask; \ - local_irq_save(__flags); \ - __mask = SMC_inw( ioaddr, INT_REG ) & ~0xff; \ - SMC_outw( __mask | (x), ioaddr, INT_REG ); \ - local_irq_restore(__flags); \ + if (SMC_CAN_USE_8BIT) \ + SMC_outb(x, ioaddr, INT_REG); \ + else { \ + unsigned long __flags; \ + int __mask; \ + local_irq_save(__flags); \ + __mask = SMC_inw( ioaddr, INT_REG ) & ~0xff; \ + SMC_outw( __mask | (x), ioaddr, INT_REG ); \ + local_irq_restore(__flags); \ + } \ + } while (0) + +#define SMC_GET_INT_MASK() \ + ( SMC_CAN_USE_8BIT ? (SMC_inb(ioaddr, IM_REG)) \ + : (SMC_inw( ioaddr, INT_REG ) >> 8) ) + +#define SMC_SET_INT_MASK(x) \ + do { \ + if (SMC_CAN_USE_8BIT) \ + SMC_outb(x, ioaddr, IM_REG); \ + else \ + SMC_outw((x) << 8, ioaddr, INT_REG); \ + } while (0) + +#define SMC_CURRENT_BANK() SMC_inw(ioaddr, BANK_SELECT) + +#define SMC_SELECT_BANK(x) \ + do { \ + if (SMC_MUST_ALIGN_WRITE) \ + SMC_outl((x)<<16, ioaddr, 12<> 8) -#define SMC_SET_INT_MASK(x) SMC_outw( (x) << 8, ioaddr, INT_REG ) -#endif -#define SMC_CURRENT_BANK() SMC_inw( ioaddr, BANK_SELECT ) -#define SMC_SELECT_BANK(x) SMC_outw( x, ioaddr, BANK_SELECT ) -#define SMC_GET_BASE() SMC_inw( ioaddr, BASE_REG ) -#define SMC_SET_BASE(x) SMC_outw( x, ioaddr, BASE_REG ) -#define SMC_GET_CONFIG() SMC_inw( ioaddr, CONFIG_REG ) -#define SMC_SET_CONFIG(x) SMC_outw( x, ioaddr, CONFIG_REG ) -#define SMC_GET_COUNTER() SMC_inw( ioaddr, COUNTER_REG ) -#define SMC_GET_CTL() SMC_inw( ioaddr, CTL_REG ) -#define SMC_SET_CTL(x) SMC_outw( x, ioaddr, CTL_REG ) -#define SMC_GET_MII() SMC_inw( ioaddr, MII_REG ) -#define SMC_SET_MII(x) SMC_outw( x, ioaddr, MII_REG ) -#define SMC_GET_MIR() SMC_inw( ioaddr, MIR_REG ) -#define SMC_SET_MIR(x) SMC_outw( x, ioaddr, MIR_REG ) -#define SMC_GET_MMU_CMD() SMC_inw( ioaddr, MMU_CMD_REG ) -#define SMC_SET_MMU_CMD(x) SMC_outw( x, ioaddr, MMU_CMD_REG ) -#define SMC_GET_FIFO() SMC_inw( ioaddr, FIFO_REG ) -#define SMC_GET_PTR() SMC_inw( ioaddr, PTR_REG ) -#define SMC_SET_PTR(x) SMC_outw( x, ioaddr, PTR_REG ) -#define SMC_GET_EPH_STATUS() SMC_inw( ioaddr, EPH_STATUS_REG ) -#define SMC_GET_RCR() SMC_inw( ioaddr, RCR_REG ) -#define SMC_SET_RCR(x) SMC_outw( x, ioaddr, RCR_REG ) -#define SMC_GET_REV() SMC_inw( ioaddr, REV_REG ) -#define SMC_GET_RPC() SMC_inw( ioaddr, RPC_REG ) -#define SMC_SET_RPC(x) SMC_outw( x, ioaddr, RPC_REG ) -#define SMC_GET_TCR() SMC_inw( ioaddr, TCR_REG ) -#define SMC_SET_TCR(x) SMC_outw( x, ioaddr, TCR_REG ) +#define SMC_GET_EPH_STATUS() SMC_inw(ioaddr, EPH_STATUS_REG) + +#define SMC_GET_RCR() SMC_inw(ioaddr, RCR_REG) + +#define SMC_SET_RCR(x) SMC_outw(x, ioaddr, RCR_REG) + +#define SMC_GET_REV() SMC_inw(ioaddr, REV_REG) + +#define SMC_GET_RPC() SMC_inw(ioaddr, RPC_REG) + +#define SMC_SET_RPC(x) \ + do { \ + if (SMC_MUST_ALIGN_WRITE) \ + SMC_outl((x)<<16, ioaddr, SMC_REG(8, 0)); \ + else \ + SMC_outw(x, ioaddr, RPC_REG); \ + } while (0) + +#define SMC_GET_TCR() SMC_inw(ioaddr, TCR_REG) + +#define SMC_SET_TCR(x) SMC_outw(x, ioaddr, TCR_REG) #ifndef SMC_GET_MAC_ADDR #define SMC_GET_MAC_ADDR(addr) \ @@ -920,151 +1079,84 @@ static const char * chip_ids[ 16 ] = { SMC_outw( mt[6] | (mt[7] << 8), ioaddr, MCAST_REG4 ); \ } while (0) -#if SMC_CAN_USE_32BIT -/* - * Some setups just can't write 8 or 16 bits reliably when not aligned - * to a 32 bit boundary. I tell you that exists! - * We re-do the ones here that can be easily worked around if they can have - * their low parts written to 0 without adverse effects. - */ -#undef SMC_SELECT_BANK -#define SMC_SELECT_BANK(x) SMC_outl( (x)<<16, ioaddr, 12<> 16; \ - } while (0) -#else #define SMC_PUT_PKT_HDR(status, length) \ do { \ - SMC_outw( status, ioaddr, DATA_REG ); \ - SMC_outw( length, ioaddr, DATA_REG ); \ - } while (0) -#define SMC_GET_PKT_HDR(status, length) \ - do { \ - (status) = SMC_inw( ioaddr, DATA_REG ); \ - (length) = SMC_inw( ioaddr, DATA_REG ); \ + if (SMC_CAN_USE_32BIT) \ + SMC_outl((status) | (length)<<16, ioaddr, DATA_REG); \ + else { \ + SMC_outw(status, ioaddr, DATA_REG); \ + SMC_outw(length, ioaddr, DATA_REG); \ + } \ } while (0) -#endif -#if SMC_CAN_USE_32BIT -#define _SMC_PUSH_DATA(p, l) \ +#define SMC_GET_PKT_HDR(status, length) \ do { \ - char *__ptr = (p); \ - int __len = (l); \ - if (__len >= 2 && (unsigned long)__ptr & 2) { \ - __len -= 2; \ - SMC_outw( *(u16 *)__ptr, ioaddr, DATA_REG ); \ - __ptr += 2; \ - } \ - SMC_outsl( ioaddr, DATA_REG, __ptr, __len >> 2); \ - if (__len & 2) { \ - __ptr += (__len & ~3); \ - SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG ); \ + if (SMC_CAN_USE_32BIT) { \ + unsigned int __val = SMC_inl(ioaddr, DATA_REG); \ + (status) = __val & 0xffff; \ + (length) = __val >> 16; \ + } else { \ + (status) = SMC_inw(ioaddr, DATA_REG); \ + (length) = SMC_inw(ioaddr, DATA_REG); \ } \ } while (0) -#define _SMC_PULL_DATA(p, l) \ - do { \ - char *__ptr = (p); \ - int __len = (l); \ - if ((unsigned long)__ptr & 2) { \ - /* \ - * We want 32bit alignment here. \ - * Since some buses perform a full 32bit \ - * fetch even for 16bit data we can't use \ - * SMC_inw() here. Back both source (on chip \ - * and destination) pointers of 2 bytes. \ - */ \ - __ptr -= 2; \ - __len += 2; \ - SMC_SET_PTR( 2|PTR_READ|PTR_RCV|PTR_AUTOINC ); \ - } \ - __len += 2; \ - SMC_insl( ioaddr, DATA_REG, __ptr, __len >> 2); \ - } while (0) -#elif SMC_CAN_USE_16BIT -#define _SMC_PUSH_DATA(p, l) SMC_outsw( ioaddr, DATA_REG, p, (l) >> 1 ) -#define _SMC_PULL_DATA(p, l) SMC_insw ( ioaddr, DATA_REG, p, (l) >> 1 ) -#elif SMC_CAN_USE_8BIT -#define _SMC_PUSH_DATA(p, l) SMC_outsb( ioaddr, DATA_REG, p, l ) -#define _SMC_PULL_DATA(p, l) SMC_insb ( ioaddr, DATA_REG, p, l ) -#endif -#if ! SMC_CAN_USE_16BIT -#define SMC_outw(x, ioaddr, reg) \ +#define SMC_PUSH_DATA(p, l) \ do { \ - unsigned int __val16 = (x); \ - SMC_outb( __val16, ioaddr, reg ); \ - SMC_outb( __val16 >> 8, ioaddr, reg + (1 << SMC_IO_SHIFT));\ + if (SMC_CAN_USE_32BIT) { \ + void *__ptr = (p); \ + int __len = (l); \ + void *__ioaddr = ioaddr; \ + if (__len >= 2 && (unsigned long)__ptr & 2) { \ + __len -= 2; \ + SMC_outw(*(u16 *)__ptr, ioaddr, DATA_REG); \ + __ptr += 2; \ + } \ + if (SMC_CAN_USE_DATACS && lp->datacs) \ + __ioaddr = lp->datacs; \ + SMC_outsl(__ioaddr, DATA_REG, __ptr, __len>>2); \ + if (__len & 2) { \ + __ptr += (__len & ~3); \ + SMC_outw(*((u16 *)__ptr), ioaddr, DATA_REG); \ + } \ + } else if (SMC_CAN_USE_16BIT) \ + SMC_outsw(ioaddr, DATA_REG, p, (l) >> 1); \ + else if (SMC_CAN_USE_8BIT) \ + SMC_outsb(ioaddr, DATA_REG, p, l); \ } while (0) -#define SMC_inw(ioaddr, reg) \ - ({ \ - unsigned int __val16; \ - __val16 = SMC_inb( ioaddr, reg ); \ - __val16 |= SMC_inb( ioaddr, reg + (1 << SMC_IO_SHIFT)) << 8; \ - __val16; \ - }) -#endif - -#ifdef SMC_CAN_USE_DATACS -#define SMC_PUSH_DATA(p, l) \ - if ( lp->datacs ) { \ - unsigned char *__ptr = (p); \ - int __len = (l); \ - if (__len >= 2 && (unsigned long)__ptr & 2) { \ - __len -= 2; \ - SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG ); \ - __ptr += 2; \ - } \ - outsl(lp->datacs, __ptr, __len >> 2); \ - if (__len & 2) { \ - __ptr += (__len & ~3); \ - SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG ); \ - } \ - } else { \ - _SMC_PUSH_DATA(p, l); \ - } #define SMC_PULL_DATA(p, l) \ - if ( lp->datacs ) { \ - unsigned char *__ptr = (p); \ - int __len = (l); \ - if ((unsigned long)__ptr & 2) { \ - /* \ - * We want 32bit alignment here. \ - * Since some buses perform a full 32bit \ - * fetch even for 16bit data we can't use \ - * SMC_inw() here. Back both source (on chip \ - * and destination) pointers of 2 bytes. \ - */ \ - __ptr -= 2; \ + do { \ + if (SMC_CAN_USE_32BIT) { \ + void *__ptr = (p); \ + int __len = (l); \ + void *__ioaddr = ioaddr; \ + if ((unsigned long)__ptr & 2) { \ + /* \ + * We want 32bit alignment here. \ + * Since some buses perform a full \ + * 32bit fetch even for 16bit data \ + * we can't use SMC_inw() here. \ + * Back both source (on-chip) and \ + * destination pointers of 2 bytes. \ + * This is possible since the call to \ + * SMC_GET_PKT_HDR() already advanced \ + * the source pointer of 4 bytes, and \ + * the skb_reserve(skb, 2) advanced \ + * the destination pointer of 2 bytes. \ + */ \ + __ptr -= 2; \ + __len += 2; \ + SMC_SET_PTR(2|PTR_READ|PTR_RCV|PTR_AUTOINC); \ + } \ + if (SMC_CAN_USE_DATACS && lp->datacs) \ + __ioaddr = lp->datacs; \ __len += 2; \ - SMC_SET_PTR( 2|PTR_READ|PTR_RCV|PTR_AUTOINC ); \ - } \ - __len += 2; \ - insl( lp->datacs, __ptr, __len >> 2); \ - } else { \ - _SMC_PULL_DATA(p, l); \ - } -#else -#define SMC_PUSH_DATA(p, l) _SMC_PUSH_DATA(p, l) -#define SMC_PULL_DATA(p, l) _SMC_PULL_DATA(p, l) -#endif - -#if !defined (SMC_INTERRUPT_PREAMBLE) -# define SMC_INTERRUPT_PREAMBLE -#endif + SMC_insl(__ioaddr, DATA_REG, __ptr, __len>>2); \ + } else if (SMC_CAN_USE_16BIT) \ + SMC_insw(ioaddr, DATA_REG, p, (l) >> 1); \ + else if (SMC_CAN_USE_8BIT) \ + SMC_insb(ioaddr, DATA_REG, p, l); \ + } while (0) #endif /* _SMC91X_H_ */ -- cgit v1.2.3 From 3d781a02313e9f22923ee919d99e1cf72fd1f468 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 16 Mar 2006 23:58:44 -0800 Subject: [PATCH] skfp warning fixes drivers/net/skfp/fplustm.c: In function `enable_formac': drivers/net/skfp/fplustm.c:552: warning: large integer implicitly truncated to unsigned type drivers/net/skfp/fplustm.c:555: warning: large integer implicitly truncated to unsigned type These arguments were changed to `const', so the compiler can now see that it's doing and outw(..., 0xffffnnnn). Cast the arg to ushort. Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/skfp/fplustm.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c index a4b2b6975d6..0784f558ca9 100644 --- a/drivers/net/skfp/fplustm.c +++ b/drivers/net/skfp/fplustm.c @@ -549,12 +549,12 @@ void formac_tx_restart(struct s_smc *smc) static void enable_formac(struct s_smc *smc) { /* set formac IMSK : 0 enables irq */ - outpw(FM_A(FM_IMSK1U),~mac_imsk1u) ; - outpw(FM_A(FM_IMSK1L),~mac_imsk1l) ; - outpw(FM_A(FM_IMSK2U),~mac_imsk2u) ; - outpw(FM_A(FM_IMSK2L),~mac_imsk2l) ; - outpw(FM_A(FM_IMSK3U),~mac_imsk3u) ; - outpw(FM_A(FM_IMSK3L),~mac_imsk3l) ; + outpw(FM_A(FM_IMSK1U),(unsigned short)~mac_imsk1u); + outpw(FM_A(FM_IMSK1L),(unsigned short)~mac_imsk1l); + outpw(FM_A(FM_IMSK2U),(unsigned short)~mac_imsk2u); + outpw(FM_A(FM_IMSK2L),(unsigned short)~mac_imsk2l); + outpw(FM_A(FM_IMSK3U),(unsigned short)~mac_imsk3u); + outpw(FM_A(FM_IMSK3L),(unsigned short)~mac_imsk3l); } #if 0 /* Removed because the driver should use the ASICs TX complete IRQ. */ -- cgit v1.2.3 From 4a5e8e296cfdeef18312c08199f25c00ec148f41 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 21 Mar 2006 16:15:44 -0500 Subject: [netdrvr] pcnet32: Lindent --- drivers/net/pcnet32.c | 4155 +++++++++++++++++++++++++------------------------ 1 file changed, 2156 insertions(+), 1999 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 1bc3f5bffb9..86136101864 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -26,8 +26,8 @@ #define DRV_RELDATE "18.Mar.2006" #define PFX DRV_NAME ": " -static const char * const version = -DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n"; +static const char *const version = + DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n"; #include #include @@ -58,18 +58,23 @@ DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " tsbogend@alpha.franken.de\n"; * PCI device identifiers for "new style" Linux PCI Device Drivers */ static struct pci_device_id pcnet32_pci_tbl[] = { - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* - * Adapters that were sold with IBM's RS/6000 or pSeries hardware have - * the incorrect vendor id. - */ - { PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, 0 }, - { 0, } + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + + /* + * Adapters that were sold with IBM's RS/6000 or pSeries hardware have + * the incorrect vendor id. + */ + { PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_AMD_LANCE, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_NETWORK_ETHERNET << 8, 0xffff00, 0}, + + { } /* terminate list */ }; -MODULE_DEVICE_TABLE (pci, pcnet32_pci_tbl); +MODULE_DEVICE_TABLE(pci, pcnet32_pci_tbl); static int cards_found; @@ -77,13 +82,11 @@ static int cards_found; * VLB I/O addresses */ static unsigned int pcnet32_portlist[] __initdata = - { 0x300, 0x320, 0x340, 0x360, 0 }; - - + { 0x300, 0x320, 0x340, 0x360, 0 }; static int pcnet32_debug = 0; -static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */ -static int pcnet32vlb; /* check for VLB cards ? */ +static int tx_start = 1; /* Mapping -- 0:20, 1:64, 2:128, 3:~220 (depends on chip vers) */ +static int pcnet32vlb; /* check for VLB cards ? */ static struct net_device *pcnet32_dev; @@ -110,32 +113,34 @@ static int rx_copybreak = 200; * to internal options */ static const unsigned char options_mapping[] = { - PCNET32_PORT_ASEL, /* 0 Auto-select */ - PCNET32_PORT_AUI, /* 1 BNC/AUI */ - PCNET32_PORT_AUI, /* 2 AUI/BNC */ - PCNET32_PORT_ASEL, /* 3 not supported */ - PCNET32_PORT_10BT | PCNET32_PORT_FD, /* 4 10baseT-FD */ - PCNET32_PORT_ASEL, /* 5 not supported */ - PCNET32_PORT_ASEL, /* 6 not supported */ - PCNET32_PORT_ASEL, /* 7 not supported */ - PCNET32_PORT_ASEL, /* 8 not supported */ - PCNET32_PORT_MII, /* 9 MII 10baseT */ - PCNET32_PORT_MII | PCNET32_PORT_FD, /* 10 MII 10baseT-FD */ - PCNET32_PORT_MII, /* 11 MII (autosel) */ - PCNET32_PORT_10BT, /* 12 10BaseT */ - PCNET32_PORT_MII | PCNET32_PORT_100, /* 13 MII 100BaseTx */ - PCNET32_PORT_MII | PCNET32_PORT_100 | PCNET32_PORT_FD, /* 14 MII 100BaseTx-FD */ - PCNET32_PORT_ASEL /* 15 not supported */ + PCNET32_PORT_ASEL, /* 0 Auto-select */ + PCNET32_PORT_AUI, /* 1 BNC/AUI */ + PCNET32_PORT_AUI, /* 2 AUI/BNC */ + PCNET32_PORT_ASEL, /* 3 not supported */ + PCNET32_PORT_10BT | PCNET32_PORT_FD, /* 4 10baseT-FD */ + PCNET32_PORT_ASEL, /* 5 not supported */ + PCNET32_PORT_ASEL, /* 6 not supported */ + PCNET32_PORT_ASEL, /* 7 not supported */ + PCNET32_PORT_ASEL, /* 8 not supported */ + PCNET32_PORT_MII, /* 9 MII 10baseT */ + PCNET32_PORT_MII | PCNET32_PORT_FD, /* 10 MII 10baseT-FD */ + PCNET32_PORT_MII, /* 11 MII (autosel) */ + PCNET32_PORT_10BT, /* 12 10BaseT */ + PCNET32_PORT_MII | PCNET32_PORT_100, /* 13 MII 100BaseTx */ + /* 14 MII 100BaseTx-FD */ + PCNET32_PORT_MII | PCNET32_PORT_100 | PCNET32_PORT_FD, + PCNET32_PORT_ASEL /* 15 not supported */ }; static const char pcnet32_gstrings_test[][ETH_GSTRING_LEN] = { - "Loopback test (offline)" + "Loopback test (offline)" }; + #define PCNET32_TEST_LEN (sizeof(pcnet32_gstrings_test) / ETH_GSTRING_LEN) #define PCNET32_NUM_REGS 136 -#define MAX_UNITS 8 /* More are supported, limit only on options */ +#define MAX_UNITS 8 /* More are supported, limit only on options */ static int options[MAX_UNITS]; static int full_duplex[MAX_UNITS]; static int homepna[MAX_UNITS]; @@ -270,7 +275,6 @@ static int homepna[MAX_UNITS]; * Philippe Seewer assisted with auto negotiation and testing. */ - /* * Set the number of Tx and Rx buffers, using Log_2(# buffers). * Reasonable default values are 4 Tx buffers, and 16 Rx buffers. @@ -306,42 +310,42 @@ static int homepna[MAX_UNITS]; /* The PCNET32 Rx and Tx ring descriptors. */ struct pcnet32_rx_head { - u32 base; - s16 buf_length; - s16 status; - u32 msg_length; - u32 reserved; + u32 base; + s16 buf_length; + s16 status; + u32 msg_length; + u32 reserved; }; struct pcnet32_tx_head { - u32 base; - s16 length; - s16 status; - u32 misc; - u32 reserved; + u32 base; + s16 length; + s16 status; + u32 misc; + u32 reserved; }; /* The PCNET32 32-Bit initialization block, described in databook. */ struct pcnet32_init_block { - u16 mode; - u16 tlen_rlen; - u8 phys_addr[6]; - u16 reserved; - u32 filter[2]; - /* Receive and transmit ring base, along with extra bits. */ - u32 rx_ring; - u32 tx_ring; + u16 mode; + u16 tlen_rlen; + u8 phys_addr[6]; + u16 reserved; + u32 filter[2]; + /* Receive and transmit ring base, along with extra bits. */ + u32 rx_ring; + u32 tx_ring; }; /* PCnet32 access functions */ struct pcnet32_access { - u16 (*read_csr)(unsigned long, int); - void (*write_csr)(unsigned long, int, u16); - u16 (*read_bcr)(unsigned long, int); - void (*write_bcr)(unsigned long, int, u16); - u16 (*read_rap)(unsigned long); - void (*write_rap)(unsigned long, u16); - void (*reset)(unsigned long); + u16 (*read_csr) (unsigned long, int); + void (*write_csr) (unsigned long, int, u16); + u16 (*read_bcr) (unsigned long, int); + void (*write_bcr) (unsigned long, int, u16); + u16 (*read_rap) (unsigned long); + void (*write_rap) (unsigned long, u16); + void (*reset) (unsigned long); }; /* @@ -349,771 +353,794 @@ struct pcnet32_access { * so the structure should be allocated using pci_alloc_consistent(). */ struct pcnet32_private { - struct pcnet32_init_block init_block; - /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ - struct pcnet32_rx_head *rx_ring; - struct pcnet32_tx_head *tx_ring; - dma_addr_t dma_addr; /* DMA address of beginning of this - object, returned by - pci_alloc_consistent */ - struct pci_dev *pci_dev; /* Pointer to the associated pci device + struct pcnet32_init_block init_block; + /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ + struct pcnet32_rx_head *rx_ring; + struct pcnet32_tx_head *tx_ring; + dma_addr_t dma_addr; /* DMA address of beginning of this + object, returned by + pci_alloc_consistent */ + struct pci_dev *pci_dev; /* Pointer to the associated pci device structure */ - const char *name; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff **tx_skbuff; - struct sk_buff **rx_skbuff; - dma_addr_t *tx_dma_addr; - dma_addr_t *rx_dma_addr; - struct pcnet32_access a; - spinlock_t lock; /* Guard lock */ - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - unsigned int rx_ring_size; /* current rx ring size */ - unsigned int tx_ring_size; /* current tx ring size */ - unsigned int rx_mod_mask; /* rx ring modular mask */ - unsigned int tx_mod_mask; /* tx ring modular mask */ - unsigned short rx_len_bits; - unsigned short tx_len_bits; - dma_addr_t rx_ring_dma_addr; - dma_addr_t tx_ring_dma_addr; - unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - struct net_device_stats stats; - char tx_full; - char phycount; /* number of phys found */ - int options; - unsigned int shared_irq:1, /* shared irq possible */ - dxsuflo:1, /* disable transmit stop on uflo */ - mii:1; /* mii port available */ - struct net_device *next; - struct mii_if_info mii_if; - struct timer_list watchdog_timer; - struct timer_list blink_timer; - u32 msg_enable; /* debug message level */ - - /* each bit indicates an available PHY */ - u32 phymask; + const char *name; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff **tx_skbuff; + struct sk_buff **rx_skbuff; + dma_addr_t *tx_dma_addr; + dma_addr_t *rx_dma_addr; + struct pcnet32_access a; + spinlock_t lock; /* Guard lock */ + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int rx_ring_size; /* current rx ring size */ + unsigned int tx_ring_size; /* current tx ring size */ + unsigned int rx_mod_mask; /* rx ring modular mask */ + unsigned int tx_mod_mask; /* tx ring modular mask */ + unsigned short rx_len_bits; + unsigned short tx_len_bits; + dma_addr_t rx_ring_dma_addr; + dma_addr_t tx_ring_dma_addr; + unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + struct net_device_stats stats; + char tx_full; + char phycount; /* number of phys found */ + int options; + unsigned int shared_irq:1, /* shared irq possible */ + dxsuflo:1, /* disable transmit stop on uflo */ + mii:1; /* mii port available */ + struct net_device *next; + struct mii_if_info mii_if; + struct timer_list watchdog_timer; + struct timer_list blink_timer; + u32 msg_enable; /* debug message level */ + + /* each bit indicates an available PHY */ + u32 phymask; }; static void pcnet32_probe_vlbus(void); -static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); -static int pcnet32_probe1(unsigned long, int, struct pci_dev *); -static int pcnet32_open(struct net_device *); -static int pcnet32_init_ring(struct net_device *); -static int pcnet32_start_xmit(struct sk_buff *, struct net_device *); -static int pcnet32_rx(struct net_device *); -static void pcnet32_tx_timeout (struct net_device *dev); +static int pcnet32_probe_pci(struct pci_dev *, const struct pci_device_id *); +static int pcnet32_probe1(unsigned long, int, struct pci_dev *); +static int pcnet32_open(struct net_device *); +static int pcnet32_init_ring(struct net_device *); +static int pcnet32_start_xmit(struct sk_buff *, struct net_device *); +static int pcnet32_rx(struct net_device *); +static void pcnet32_tx_timeout(struct net_device *dev); static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *); -static int pcnet32_close(struct net_device *); +static int pcnet32_close(struct net_device *); static struct net_device_stats *pcnet32_get_stats(struct net_device *); static void pcnet32_load_multicast(struct net_device *dev); static void pcnet32_set_multicast_list(struct net_device *); -static int pcnet32_ioctl(struct net_device *, struct ifreq *, int); +static int pcnet32_ioctl(struct net_device *, struct ifreq *, int); static void pcnet32_watchdog(struct net_device *); static int mdio_read(struct net_device *dev, int phy_id, int reg_num); -static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val); +static void mdio_write(struct net_device *dev, int phy_id, int reg_num, + int val); static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits); static void pcnet32_ethtool_test(struct net_device *dev, - struct ethtool_test *eth_test, u64 *data); -static int pcnet32_loopback_test(struct net_device *dev, uint64_t *data1); + struct ethtool_test *eth_test, u64 * data); +static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1); static int pcnet32_phys_id(struct net_device *dev, u32 data); static void pcnet32_led_blink_callback(struct net_device *dev); static int pcnet32_get_regs_len(struct net_device *dev); static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, - void *ptr); + void *ptr); static void pcnet32_purge_tx_ring(struct net_device *dev); static int pcnet32_alloc_ring(struct net_device *dev, char *name); static void pcnet32_free_ring(struct net_device *dev); static void pcnet32_check_media(struct net_device *dev, int verbose); - enum pci_flags_bit { - PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, - PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, + PCI_USES_IO = 1, PCI_USES_MEM = 2, PCI_USES_MASTER = 4, + PCI_ADDR0 = 0x10 << 0, PCI_ADDR1 = 0x10 << 1, PCI_ADDR2 = + 0x10 << 2, PCI_ADDR3 = 0x10 << 3, }; - -static u16 pcnet32_wio_read_csr (unsigned long addr, int index) +static u16 pcnet32_wio_read_csr(unsigned long addr, int index) { - outw (index, addr+PCNET32_WIO_RAP); - return inw (addr+PCNET32_WIO_RDP); + outw(index, addr + PCNET32_WIO_RAP); + return inw(addr + PCNET32_WIO_RDP); } -static void pcnet32_wio_write_csr (unsigned long addr, int index, u16 val) +static void pcnet32_wio_write_csr(unsigned long addr, int index, u16 val) { - outw (index, addr+PCNET32_WIO_RAP); - outw (val, addr+PCNET32_WIO_RDP); + outw(index, addr + PCNET32_WIO_RAP); + outw(val, addr + PCNET32_WIO_RDP); } -static u16 pcnet32_wio_read_bcr (unsigned long addr, int index) +static u16 pcnet32_wio_read_bcr(unsigned long addr, int index) { - outw (index, addr+PCNET32_WIO_RAP); - return inw (addr+PCNET32_WIO_BDP); + outw(index, addr + PCNET32_WIO_RAP); + return inw(addr + PCNET32_WIO_BDP); } -static void pcnet32_wio_write_bcr (unsigned long addr, int index, u16 val) +static void pcnet32_wio_write_bcr(unsigned long addr, int index, u16 val) { - outw (index, addr+PCNET32_WIO_RAP); - outw (val, addr+PCNET32_WIO_BDP); + outw(index, addr + PCNET32_WIO_RAP); + outw(val, addr + PCNET32_WIO_BDP); } -static u16 pcnet32_wio_read_rap (unsigned long addr) +static u16 pcnet32_wio_read_rap(unsigned long addr) { - return inw (addr+PCNET32_WIO_RAP); + return inw(addr + PCNET32_WIO_RAP); } -static void pcnet32_wio_write_rap (unsigned long addr, u16 val) +static void pcnet32_wio_write_rap(unsigned long addr, u16 val) { - outw (val, addr+PCNET32_WIO_RAP); + outw(val, addr + PCNET32_WIO_RAP); } -static void pcnet32_wio_reset (unsigned long addr) +static void pcnet32_wio_reset(unsigned long addr) { - inw (addr+PCNET32_WIO_RESET); + inw(addr + PCNET32_WIO_RESET); } -static int pcnet32_wio_check (unsigned long addr) +static int pcnet32_wio_check(unsigned long addr) { - outw (88, addr+PCNET32_WIO_RAP); - return (inw (addr+PCNET32_WIO_RAP) == 88); + outw(88, addr + PCNET32_WIO_RAP); + return (inw(addr + PCNET32_WIO_RAP) == 88); } static struct pcnet32_access pcnet32_wio = { - .read_csr = pcnet32_wio_read_csr, - .write_csr = pcnet32_wio_write_csr, - .read_bcr = pcnet32_wio_read_bcr, - .write_bcr = pcnet32_wio_write_bcr, - .read_rap = pcnet32_wio_read_rap, - .write_rap = pcnet32_wio_write_rap, - .reset = pcnet32_wio_reset + .read_csr = pcnet32_wio_read_csr, + .write_csr = pcnet32_wio_write_csr, + .read_bcr = pcnet32_wio_read_bcr, + .write_bcr = pcnet32_wio_write_bcr, + .read_rap = pcnet32_wio_read_rap, + .write_rap = pcnet32_wio_write_rap, + .reset = pcnet32_wio_reset }; -static u16 pcnet32_dwio_read_csr (unsigned long addr, int index) +static u16 pcnet32_dwio_read_csr(unsigned long addr, int index) { - outl (index, addr+PCNET32_DWIO_RAP); - return (inl (addr+PCNET32_DWIO_RDP) & 0xffff); + outl(index, addr + PCNET32_DWIO_RAP); + return (inl(addr + PCNET32_DWIO_RDP) & 0xffff); } -static void pcnet32_dwio_write_csr (unsigned long addr, int index, u16 val) +static void pcnet32_dwio_write_csr(unsigned long addr, int index, u16 val) { - outl (index, addr+PCNET32_DWIO_RAP); - outl (val, addr+PCNET32_DWIO_RDP); + outl(index, addr + PCNET32_DWIO_RAP); + outl(val, addr + PCNET32_DWIO_RDP); } -static u16 pcnet32_dwio_read_bcr (unsigned long addr, int index) +static u16 pcnet32_dwio_read_bcr(unsigned long addr, int index) { - outl (index, addr+PCNET32_DWIO_RAP); - return (inl (addr+PCNET32_DWIO_BDP) & 0xffff); + outl(index, addr + PCNET32_DWIO_RAP); + return (inl(addr + PCNET32_DWIO_BDP) & 0xffff); } -static void pcnet32_dwio_write_bcr (unsigned long addr, int index, u16 val) +static void pcnet32_dwio_write_bcr(unsigned long addr, int index, u16 val) { - outl (index, addr+PCNET32_DWIO_RAP); - outl (val, addr+PCNET32_DWIO_BDP); + outl(index, addr + PCNET32_DWIO_RAP); + outl(val, addr + PCNET32_DWIO_BDP); } -static u16 pcnet32_dwio_read_rap (unsigned long addr) +static u16 pcnet32_dwio_read_rap(unsigned long addr) { - return (inl (addr+PCNET32_DWIO_RAP) & 0xffff); + return (inl(addr + PCNET32_DWIO_RAP) & 0xffff); } -static void pcnet32_dwio_write_rap (unsigned long addr, u16 val) +static void pcnet32_dwio_write_rap(unsigned long addr, u16 val) { - outl (val, addr+PCNET32_DWIO_RAP); + outl(val, addr + PCNET32_DWIO_RAP); } -static void pcnet32_dwio_reset (unsigned long addr) +static void pcnet32_dwio_reset(unsigned long addr) { - inl (addr+PCNET32_DWIO_RESET); + inl(addr + PCNET32_DWIO_RESET); } -static int pcnet32_dwio_check (unsigned long addr) +static int pcnet32_dwio_check(unsigned long addr) { - outl (88, addr+PCNET32_DWIO_RAP); - return ((inl (addr+PCNET32_DWIO_RAP) & 0xffff) == 88); + outl(88, addr + PCNET32_DWIO_RAP); + return ((inl(addr + PCNET32_DWIO_RAP) & 0xffff) == 88); } static struct pcnet32_access pcnet32_dwio = { - .read_csr = pcnet32_dwio_read_csr, - .write_csr = pcnet32_dwio_write_csr, - .read_bcr = pcnet32_dwio_read_bcr, - .write_bcr = pcnet32_dwio_write_bcr, - .read_rap = pcnet32_dwio_read_rap, - .write_rap = pcnet32_dwio_write_rap, - .reset = pcnet32_dwio_reset + .read_csr = pcnet32_dwio_read_csr, + .write_csr = pcnet32_dwio_write_csr, + .read_bcr = pcnet32_dwio_read_bcr, + .write_bcr = pcnet32_dwio_write_bcr, + .read_rap = pcnet32_dwio_read_rap, + .write_rap = pcnet32_dwio_write_rap, + .reset = pcnet32_dwio_reset }; #ifdef CONFIG_NET_POLL_CONTROLLER static void pcnet32_poll_controller(struct net_device *dev) { - disable_irq(dev->irq); - pcnet32_interrupt(0, dev, NULL); - enable_irq(dev->irq); + disable_irq(dev->irq); + pcnet32_interrupt(0, dev, NULL); + enable_irq(dev->irq); } #endif - static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct pcnet32_private *lp = dev->priv; - unsigned long flags; - int r = -EOPNOTSUPP; + struct pcnet32_private *lp = dev->priv; + unsigned long flags; + int r = -EOPNOTSUPP; - if (lp->mii) { - spin_lock_irqsave(&lp->lock, flags); - mii_ethtool_gset(&lp->mii_if, cmd); - spin_unlock_irqrestore(&lp->lock, flags); - r = 0; - } - return r; + if (lp->mii) { + spin_lock_irqsave(&lp->lock, flags); + mii_ethtool_gset(&lp->mii_if, cmd); + spin_unlock_irqrestore(&lp->lock, flags); + r = 0; + } + return r; } static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct pcnet32_private *lp = dev->priv; - unsigned long flags; - int r = -EOPNOTSUPP; + struct pcnet32_private *lp = dev->priv; + unsigned long flags; + int r = -EOPNOTSUPP; - if (lp->mii) { - spin_lock_irqsave(&lp->lock, flags); - r = mii_ethtool_sset(&lp->mii_if, cmd); - spin_unlock_irqrestore(&lp->lock, flags); - } - return r; + if (lp->mii) { + spin_lock_irqsave(&lp->lock, flags); + r = mii_ethtool_sset(&lp->mii_if, cmd); + spin_unlock_irqrestore(&lp->lock, flags); + } + return r; } -static void pcnet32_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +static void pcnet32_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) { - struct pcnet32_private *lp = dev->priv; - - strcpy (info->driver, DRV_NAME); - strcpy (info->version, DRV_VERSION); - if (lp->pci_dev) - strcpy (info->bus_info, pci_name(lp->pci_dev)); - else - sprintf(info->bus_info, "VLB 0x%lx", dev->base_addr); + struct pcnet32_private *lp = dev->priv; + + strcpy(info->driver, DRV_NAME); + strcpy(info->version, DRV_VERSION); + if (lp->pci_dev) + strcpy(info->bus_info, pci_name(lp->pci_dev)); + else + sprintf(info->bus_info, "VLB 0x%lx", dev->base_addr); } static u32 pcnet32_get_link(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - unsigned long flags; - int r; - - spin_lock_irqsave(&lp->lock, flags); - if (lp->mii) { - r = mii_link_ok(&lp->mii_if); - } else { - ulong ioaddr = dev->base_addr; /* card base I/O address */ - r = (lp->a.read_bcr(ioaddr, 4) != 0xc0); - } - spin_unlock_irqrestore(&lp->lock, flags); + struct pcnet32_private *lp = dev->priv; + unsigned long flags; + int r; - return r; + spin_lock_irqsave(&lp->lock, flags); + if (lp->mii) { + r = mii_link_ok(&lp->mii_if); + } else { + ulong ioaddr = dev->base_addr; /* card base I/O address */ + r = (lp->a.read_bcr(ioaddr, 4) != 0xc0); + } + spin_unlock_irqrestore(&lp->lock, flags); + + return r; } static u32 pcnet32_get_msglevel(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - return lp->msg_enable; + struct pcnet32_private *lp = dev->priv; + return lp->msg_enable; } static void pcnet32_set_msglevel(struct net_device *dev, u32 value) { - struct pcnet32_private *lp = dev->priv; - lp->msg_enable = value; + struct pcnet32_private *lp = dev->priv; + lp->msg_enable = value; } static int pcnet32_nway_reset(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - unsigned long flags; - int r = -EOPNOTSUPP; + struct pcnet32_private *lp = dev->priv; + unsigned long flags; + int r = -EOPNOTSUPP; - if (lp->mii) { - spin_lock_irqsave(&lp->lock, flags); - r = mii_nway_restart(&lp->mii_if); - spin_unlock_irqrestore(&lp->lock, flags); - } - return r; + if (lp->mii) { + spin_lock_irqsave(&lp->lock, flags); + r = mii_nway_restart(&lp->mii_if); + spin_unlock_irqrestore(&lp->lock, flags); + } + return r; } -static void pcnet32_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) +static void pcnet32_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ering) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = dev->priv; - ering->tx_max_pending = TX_MAX_RING_SIZE - 1; - ering->tx_pending = lp->tx_ring_size - 1; - ering->rx_max_pending = RX_MAX_RING_SIZE - 1; - ering->rx_pending = lp->rx_ring_size - 1; + ering->tx_max_pending = TX_MAX_RING_SIZE - 1; + ering->tx_pending = lp->tx_ring_size - 1; + ering->rx_max_pending = RX_MAX_RING_SIZE - 1; + ering->rx_pending = lp->rx_ring_size - 1; } -static int pcnet32_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) +static int pcnet32_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *ering) { - struct pcnet32_private *lp = dev->priv; - unsigned long flags; - int i; - - if (ering->rx_mini_pending || ering->rx_jumbo_pending) - return -EINVAL; - - if (netif_running(dev)) - pcnet32_close(dev); - - spin_lock_irqsave(&lp->lock, flags); - pcnet32_free_ring(dev); - lp->tx_ring_size = min(ering->tx_pending, (unsigned int) TX_MAX_RING_SIZE); - lp->rx_ring_size = min(ering->rx_pending, (unsigned int) RX_MAX_RING_SIZE); - - /* set the minimum ring size to 4, to allow the loopback test to work - * unchanged. - */ - for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) { - if (lp->tx_ring_size <= (1 << i)) - break; - } - lp->tx_ring_size = (1 << i); - lp->tx_mod_mask = lp->tx_ring_size - 1; - lp->tx_len_bits = (i << 12); - - for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) { - if (lp->rx_ring_size <= (1 << i)) - break; - } - lp->rx_ring_size = (1 << i); - lp->rx_mod_mask = lp->rx_ring_size - 1; - lp->rx_len_bits = (i << 4); - - if (pcnet32_alloc_ring(dev, dev->name)) { + struct pcnet32_private *lp = dev->priv; + unsigned long flags; + int i; + + if (ering->rx_mini_pending || ering->rx_jumbo_pending) + return -EINVAL; + + if (netif_running(dev)) + pcnet32_close(dev); + + spin_lock_irqsave(&lp->lock, flags); pcnet32_free_ring(dev); - spin_unlock_irqrestore(&lp->lock, flags); - return -ENOMEM; - } + lp->tx_ring_size = + min(ering->tx_pending, (unsigned int)TX_MAX_RING_SIZE); + lp->rx_ring_size = + min(ering->rx_pending, (unsigned int)RX_MAX_RING_SIZE); + + /* set the minimum ring size to 4, to allow the loopback test to work + * unchanged. + */ + for (i = 2; i <= PCNET32_LOG_MAX_TX_BUFFERS; i++) { + if (lp->tx_ring_size <= (1 << i)) + break; + } + lp->tx_ring_size = (1 << i); + lp->tx_mod_mask = lp->tx_ring_size - 1; + lp->tx_len_bits = (i << 12); - spin_unlock_irqrestore(&lp->lock, flags); + for (i = 2; i <= PCNET32_LOG_MAX_RX_BUFFERS; i++) { + if (lp->rx_ring_size <= (1 << i)) + break; + } + lp->rx_ring_size = (1 << i); + lp->rx_mod_mask = lp->rx_ring_size - 1; + lp->rx_len_bits = (i << 4); + + if (pcnet32_alloc_ring(dev, dev->name)) { + pcnet32_free_ring(dev); + spin_unlock_irqrestore(&lp->lock, flags); + return -ENOMEM; + } - if (pcnet32_debug & NETIF_MSG_DRV) - printk(KERN_INFO PFX "%s: Ring Param Settings: RX: %d, TX: %d\n", - dev->name, lp->rx_ring_size, lp->tx_ring_size); + spin_unlock_irqrestore(&lp->lock, flags); - if (netif_running(dev)) - pcnet32_open(dev); + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_INFO PFX + "%s: Ring Param Settings: RX: %d, TX: %d\n", dev->name, + lp->rx_ring_size, lp->tx_ring_size); - return 0; + if (netif_running(dev)) + pcnet32_open(dev); + + return 0; } -static void pcnet32_get_strings(struct net_device *dev, u32 stringset, u8 *data) +static void pcnet32_get_strings(struct net_device *dev, u32 stringset, + u8 * data) { - memcpy(data, pcnet32_gstrings_test, sizeof(pcnet32_gstrings_test)); + memcpy(data, pcnet32_gstrings_test, sizeof(pcnet32_gstrings_test)); } static int pcnet32_self_test_count(struct net_device *dev) { - return PCNET32_TEST_LEN; + return PCNET32_TEST_LEN; } static void pcnet32_ethtool_test(struct net_device *dev, - struct ethtool_test *test, u64 *data) + struct ethtool_test *test, u64 * data) { - struct pcnet32_private *lp = dev->priv; - int rc; - - if (test->flags == ETH_TEST_FL_OFFLINE) { - rc = pcnet32_loopback_test(dev, data); - if (rc) { - if (netif_msg_hw(lp)) - printk(KERN_DEBUG "%s: Loopback test failed.\n", dev->name); - test->flags |= ETH_TEST_FL_FAILED; + struct pcnet32_private *lp = dev->priv; + int rc; + + if (test->flags == ETH_TEST_FL_OFFLINE) { + rc = pcnet32_loopback_test(dev, data); + if (rc) { + if (netif_msg_hw(lp)) + printk(KERN_DEBUG "%s: Loopback test failed.\n", + dev->name); + test->flags |= ETH_TEST_FL_FAILED; + } else if (netif_msg_hw(lp)) + printk(KERN_DEBUG "%s: Loopback test passed.\n", + dev->name); } else if (netif_msg_hw(lp)) - printk(KERN_DEBUG "%s: Loopback test passed.\n", dev->name); - } else if (netif_msg_hw(lp)) - printk(KERN_DEBUG "%s: No tests to run (specify 'Offline' on ethtool).", dev->name); -} /* end pcnet32_ethtool_test */ + printk(KERN_DEBUG + "%s: No tests to run (specify 'Offline' on ethtool).", + dev->name); +} /* end pcnet32_ethtool_test */ -static int pcnet32_loopback_test(struct net_device *dev, uint64_t *data1) +static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) { - struct pcnet32_private *lp = dev->priv; - struct pcnet32_access *a = &lp->a; /* access to registers */ - ulong ioaddr = dev->base_addr; /* card base I/O address */ - struct sk_buff *skb; /* sk buff */ - int x, i; /* counters */ - int numbuffs = 4; /* number of TX/RX buffers and descs */ - u16 status = 0x8300; /* TX ring status */ - u16 teststatus; /* test of ring status */ - int rc; /* return code */ - int size; /* size of packets */ - unsigned char *packet; /* source packet data */ - static const int data_len = 60; /* length of source packets */ - unsigned long flags; - unsigned long ticks; - - *data1 = 1; /* status of test, default to fail */ - rc = 1; /* default to fail */ - - if (netif_running(dev)) - pcnet32_close(dev); - - spin_lock_irqsave(&lp->lock, flags); - - /* Reset the PCNET32 */ - lp->a.reset (ioaddr); - - /* switch pcnet32 to 32bit mode */ - lp->a.write_bcr (ioaddr, 20, 2); - - lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); - lp->init_block.filter[0] = 0; - lp->init_block.filter[1] = 0; - - /* purge & init rings but don't actually restart */ - pcnet32_restart(dev, 0x0000); - - lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */ - - /* Initialize Transmit buffers. */ - size = data_len + 15; - for (x=0; xname, __LINE__); - goto clean_up; - } else { - packet = skb->data; - skb_put(skb, size); /* create space for data */ - lp->tx_skbuff[x] = skb; - lp->tx_ring[x].length = le16_to_cpu(-skb->len); - lp->tx_ring[x].misc = 0; - - /* put DA and SA into the skb */ - for (i=0; i<6; i++) - *packet++ = dev->dev_addr[i]; - for (i=0; i<6; i++) - *packet++ = dev->dev_addr[i]; - /* type */ - *packet++ = 0x08; - *packet++ = 0x06; - /* packet number */ - *packet++ = x; - /* fill packet with data */ - for (i=0; itx_dma_addr[x] = pci_map_single(lp->pci_dev, skb->data, - skb->len, PCI_DMA_TODEVICE); - lp->tx_ring[x].base = (u32)le32_to_cpu(lp->tx_dma_addr[x]); - wmb(); /* Make sure owner changes after all others are visible */ - lp->tx_ring[x].status = le16_to_cpu(status); - } - } - - x = a->read_bcr(ioaddr, 32); /* set internal loopback in BSR32 */ - x = x | 0x0002; - a->write_bcr(ioaddr, 32, x); - - lp->a.write_csr (ioaddr, 15, 0x0044); /* set int loopback in CSR15 */ - - teststatus = le16_to_cpu(0x8000); - lp->a.write_csr(ioaddr, 0, 0x0002); /* Set STRT bit */ - - /* Check status of descriptors */ - for (x=0; xrx_ring[x].status & teststatus) && (ticks < 200)) { - spin_unlock_irqrestore(&lp->lock, flags); - mdelay(1); - spin_lock_irqsave(&lp->lock, flags); - rmb(); - ticks++; - } - if (ticks == 200) { - if (netif_msg_hw(lp)) - printk("%s: Desc %d failed to reset!\n",dev->name,x); - break; - } - } - - lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */ - wmb(); - if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) { - printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name); - - for (x=0; xname, x); - skb = lp->rx_skbuff[x]; - for (i=0; idata+i)); - } - printk("\n"); - } - } - - x = 0; - rc = 0; - while (xrx_skbuff[x]; - packet = lp->tx_skbuff[x]->data; - for (i=0; idata+i) != packet[i]) { - if (netif_msg_hw(lp)) - printk(KERN_DEBUG "%s: Error in compare! %2x - %02x %02x\n", - dev->name, i, *(skb->data+i), packet[i]); - rc = 1; - break; - } + struct pcnet32_private *lp = dev->priv; + struct pcnet32_access *a = &lp->a; /* access to registers */ + ulong ioaddr = dev->base_addr; /* card base I/O address */ + struct sk_buff *skb; /* sk buff */ + int x, i; /* counters */ + int numbuffs = 4; /* number of TX/RX buffers and descs */ + u16 status = 0x8300; /* TX ring status */ + u16 teststatus; /* test of ring status */ + int rc; /* return code */ + int size; /* size of packets */ + unsigned char *packet; /* source packet data */ + static const int data_len = 60; /* length of source packets */ + unsigned long flags; + unsigned long ticks; + + *data1 = 1; /* status of test, default to fail */ + rc = 1; /* default to fail */ + + if (netif_running(dev)) + pcnet32_close(dev); + + spin_lock_irqsave(&lp->lock, flags); + + /* Reset the PCNET32 */ + lp->a.reset(ioaddr); + + /* switch pcnet32 to 32bit mode */ + lp->a.write_bcr(ioaddr, 20, 2); + + lp->init_block.mode = + le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); + lp->init_block.filter[0] = 0; + lp->init_block.filter[1] = 0; + + /* purge & init rings but don't actually restart */ + pcnet32_restart(dev, 0x0000); + + lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */ + + /* Initialize Transmit buffers. */ + size = data_len + 15; + for (x = 0; x < numbuffs; x++) { + if (!(skb = dev_alloc_skb(size))) { + if (netif_msg_hw(lp)) + printk(KERN_DEBUG + "%s: Cannot allocate skb at line: %d!\n", + dev->name, __LINE__); + goto clean_up; + } else { + packet = skb->data; + skb_put(skb, size); /* create space for data */ + lp->tx_skbuff[x] = skb; + lp->tx_ring[x].length = le16_to_cpu(-skb->len); + lp->tx_ring[x].misc = 0; + + /* put DA and SA into the skb */ + for (i = 0; i < 6; i++) + *packet++ = dev->dev_addr[i]; + for (i = 0; i < 6; i++) + *packet++ = dev->dev_addr[i]; + /* type */ + *packet++ = 0x08; + *packet++ = 0x06; + /* packet number */ + *packet++ = x; + /* fill packet with data */ + for (i = 0; i < data_len; i++) + *packet++ = i; + + lp->tx_dma_addr[x] = + pci_map_single(lp->pci_dev, skb->data, skb->len, + PCI_DMA_TODEVICE); + lp->tx_ring[x].base = + (u32) le32_to_cpu(lp->tx_dma_addr[x]); + wmb(); /* Make sure owner changes after all others are visible */ + lp->tx_ring[x].status = le16_to_cpu(status); + } } - x++; - } - if (!rc) { - *data1 = 0; - } -clean_up: - pcnet32_purge_tx_ring(dev); - x = a->read_csr(ioaddr, 15) & 0xFFFF; - a->write_csr(ioaddr, 15, (x & ~0x0044)); /* reset bits 6 and 2 */ + x = a->read_bcr(ioaddr, 32); /* set internal loopback in BSR32 */ + x = x | 0x0002; + a->write_bcr(ioaddr, 32, x); + + lp->a.write_csr(ioaddr, 15, 0x0044); /* set int loopback in CSR15 */ + + teststatus = le16_to_cpu(0x8000); + lp->a.write_csr(ioaddr, 0, 0x0002); /* Set STRT bit */ + + /* Check status of descriptors */ + for (x = 0; x < numbuffs; x++) { + ticks = 0; + rmb(); + while ((lp->rx_ring[x].status & teststatus) && (ticks < 200)) { + spin_unlock_irqrestore(&lp->lock, flags); + mdelay(1); + spin_lock_irqsave(&lp->lock, flags); + rmb(); + ticks++; + } + if (ticks == 200) { + if (netif_msg_hw(lp)) + printk("%s: Desc %d failed to reset!\n", + dev->name, x); + break; + } + } + + lp->a.write_csr(ioaddr, 0, 0x0004); /* Set STOP bit */ + wmb(); + if (netif_msg_hw(lp) && netif_msg_pktdata(lp)) { + printk(KERN_DEBUG "%s: RX loopback packets:\n", dev->name); + + for (x = 0; x < numbuffs; x++) { + printk(KERN_DEBUG "%s: Packet %d:\n", dev->name, x); + skb = lp->rx_skbuff[x]; + for (i = 0; i < size; i++) { + printk("%02x ", *(skb->data + i)); + } + printk("\n"); + } + } - x = a->read_bcr(ioaddr, 32); /* reset internal loopback */ - x = x & ~0x0002; - a->write_bcr(ioaddr, 32, x); + x = 0; + rc = 0; + while (x < numbuffs && !rc) { + skb = lp->rx_skbuff[x]; + packet = lp->tx_skbuff[x]->data; + for (i = 0; i < size; i++) { + if (*(skb->data + i) != packet[i]) { + if (netif_msg_hw(lp)) + printk(KERN_DEBUG + "%s: Error in compare! %2x - %02x %02x\n", + dev->name, i, *(skb->data + i), + packet[i]); + rc = 1; + break; + } + } + x++; + } + if (!rc) { + *data1 = 0; + } - spin_unlock_irqrestore(&lp->lock, flags); + clean_up: + pcnet32_purge_tx_ring(dev); + x = a->read_csr(ioaddr, 15) & 0xFFFF; + a->write_csr(ioaddr, 15, (x & ~0x0044)); /* reset bits 6 and 2 */ - if (netif_running(dev)) { - pcnet32_open(dev); - } else { - lp->a.write_bcr (ioaddr, 20, 4); /* return to 16bit mode */ - } + x = a->read_bcr(ioaddr, 32); /* reset internal loopback */ + x = x & ~0x0002; + a->write_bcr(ioaddr, 32, x); - return(rc); -} /* end pcnet32_loopback_test */ + spin_unlock_irqrestore(&lp->lock, flags); + + if (netif_running(dev)) { + pcnet32_open(dev); + } else { + lp->a.write_bcr(ioaddr, 20, 4); /* return to 16bit mode */ + } + + return (rc); +} /* end pcnet32_loopback_test */ static void pcnet32_led_blink_callback(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - struct pcnet32_access *a = &lp->a; - ulong ioaddr = dev->base_addr; - unsigned long flags; - int i; - - spin_lock_irqsave(&lp->lock, flags); - for (i=4; i<8; i++) { - a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000); - } - spin_unlock_irqrestore(&lp->lock, flags); - - mod_timer(&lp->blink_timer, PCNET32_BLINK_TIMEOUT); + struct pcnet32_private *lp = dev->priv; + struct pcnet32_access *a = &lp->a; + ulong ioaddr = dev->base_addr; + unsigned long flags; + int i; + + spin_lock_irqsave(&lp->lock, flags); + for (i = 4; i < 8; i++) { + a->write_bcr(ioaddr, i, a->read_bcr(ioaddr, i) ^ 0x4000); + } + spin_unlock_irqrestore(&lp->lock, flags); + + mod_timer(&lp->blink_timer, PCNET32_BLINK_TIMEOUT); } static int pcnet32_phys_id(struct net_device *dev, u32 data) { - struct pcnet32_private *lp = dev->priv; - struct pcnet32_access *a = &lp->a; - ulong ioaddr = dev->base_addr; - unsigned long flags; - int i, regs[4]; - - if (!lp->blink_timer.function) { - init_timer(&lp->blink_timer); - lp->blink_timer.function = (void *) pcnet32_led_blink_callback; - lp->blink_timer.data = (unsigned long) dev; - } - - /* Save the current value of the bcrs */ - spin_lock_irqsave(&lp->lock, flags); - for (i=4; i<8; i++) { - regs[i-4] = a->read_bcr(ioaddr, i); - } - spin_unlock_irqrestore(&lp->lock, flags); - - mod_timer(&lp->blink_timer, jiffies); - set_current_state(TASK_INTERRUPTIBLE); - - if ((!data) || (data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))) - data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ); - - msleep_interruptible(data * 1000); - del_timer_sync(&lp->blink_timer); - - /* Restore the original value of the bcrs */ - spin_lock_irqsave(&lp->lock, flags); - for (i=4; i<8; i++) { - a->write_bcr(ioaddr, i, regs[i-4]); - } - spin_unlock_irqrestore(&lp->lock, flags); - - return 0; + struct pcnet32_private *lp = dev->priv; + struct pcnet32_access *a = &lp->a; + ulong ioaddr = dev->base_addr; + unsigned long flags; + int i, regs[4]; + + if (!lp->blink_timer.function) { + init_timer(&lp->blink_timer); + lp->blink_timer.function = (void *)pcnet32_led_blink_callback; + lp->blink_timer.data = (unsigned long)dev; + } + + /* Save the current value of the bcrs */ + spin_lock_irqsave(&lp->lock, flags); + for (i = 4; i < 8; i++) { + regs[i - 4] = a->read_bcr(ioaddr, i); + } + spin_unlock_irqrestore(&lp->lock, flags); + + mod_timer(&lp->blink_timer, jiffies); + set_current_state(TASK_INTERRUPTIBLE); + + if ((!data) || (data > (u32) (MAX_SCHEDULE_TIMEOUT / HZ))) + data = (u32) (MAX_SCHEDULE_TIMEOUT / HZ); + + msleep_interruptible(data * 1000); + del_timer_sync(&lp->blink_timer); + + /* Restore the original value of the bcrs */ + spin_lock_irqsave(&lp->lock, flags); + for (i = 4; i < 8; i++) { + a->write_bcr(ioaddr, i, regs[i - 4]); + } + spin_unlock_irqrestore(&lp->lock, flags); + + return 0; } #define PCNET32_REGS_PER_PHY 32 #define PCNET32_MAX_PHYS 32 static int pcnet32_get_regs_len(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - int j = lp->phycount * PCNET32_REGS_PER_PHY; + struct pcnet32_private *lp = dev->priv; + int j = lp->phycount * PCNET32_REGS_PER_PHY; - return((PCNET32_NUM_REGS + j) * sizeof(u16)); + return ((PCNET32_NUM_REGS + j) * sizeof(u16)); } static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, - void *ptr) + void *ptr) { - int i, csr0; - u16 *buff = ptr; - struct pcnet32_private *lp = dev->priv; - struct pcnet32_access *a = &lp->a; - ulong ioaddr = dev->base_addr; - int ticks; - unsigned long flags; - - spin_lock_irqsave(&lp->lock, flags); - - csr0 = a->read_csr(ioaddr, 0); - if (!(csr0 & 0x0004)) { /* If not stopped */ - /* set SUSPEND (SPND) - CSR5 bit 0 */ - a->write_csr(ioaddr, 5, 0x0001); - - /* poll waiting for bit to be set */ - ticks = 0; - while (!(a->read_csr(ioaddr, 5) & 0x0001)) { - spin_unlock_irqrestore(&lp->lock, flags); - mdelay(1); - spin_lock_irqsave(&lp->lock, flags); - ticks++; - if (ticks > 200) { - if (netif_msg_hw(lp)) - printk(KERN_DEBUG "%s: Error getting into suspend!\n", - dev->name); - break; - } - } - } - - /* read address PROM */ - for (i=0; i<16; i += 2) - *buff++ = inw(ioaddr + i); - - /* read control and status registers */ - for (i=0; i<90; i++) { - *buff++ = a->read_csr(ioaddr, i); - } - - *buff++ = a->read_csr(ioaddr, 112); - *buff++ = a->read_csr(ioaddr, 114); - - /* read bus configuration registers */ - for (i=0; i<30; i++) { - *buff++ = a->read_bcr(ioaddr, i); - } - *buff++ = 0; /* skip bcr30 so as not to hang 79C976 */ - for (i=31; i<36; i++) { - *buff++ = a->read_bcr(ioaddr, i); - } - - /* read mii phy registers */ - if (lp->mii) { - int j; - for (j=0; jphymask & (1 << j)) { - for (i=0; ia.write_bcr(ioaddr, 33, (j << 5) | i); - *buff++ = lp->a.read_bcr(ioaddr, 34); + int i, csr0; + u16 *buff = ptr; + struct pcnet32_private *lp = dev->priv; + struct pcnet32_access *a = &lp->a; + ulong ioaddr = dev->base_addr; + int ticks; + unsigned long flags; + + spin_lock_irqsave(&lp->lock, flags); + + csr0 = a->read_csr(ioaddr, 0); + if (!(csr0 & 0x0004)) { /* If not stopped */ + /* set SUSPEND (SPND) - CSR5 bit 0 */ + a->write_csr(ioaddr, 5, 0x0001); + + /* poll waiting for bit to be set */ + ticks = 0; + while (!(a->read_csr(ioaddr, 5) & 0x0001)) { + spin_unlock_irqrestore(&lp->lock, flags); + mdelay(1); + spin_lock_irqsave(&lp->lock, flags); + ticks++; + if (ticks > 200) { + if (netif_msg_hw(lp)) + printk(KERN_DEBUG + "%s: Error getting into suspend!\n", + dev->name); + break; + } } - } } - } - if (!(csr0 & 0x0004)) { /* If not stopped */ - /* clear SUSPEND (SPND) - CSR5 bit 0 */ - a->write_csr(ioaddr, 5, 0x0000); - } + /* read address PROM */ + for (i = 0; i < 16; i += 2) + *buff++ = inw(ioaddr + i); + + /* read control and status registers */ + for (i = 0; i < 90; i++) { + *buff++ = a->read_csr(ioaddr, i); + } + + *buff++ = a->read_csr(ioaddr, 112); + *buff++ = a->read_csr(ioaddr, 114); - spin_unlock_irqrestore(&lp->lock, flags); + /* read bus configuration registers */ + for (i = 0; i < 30; i++) { + *buff++ = a->read_bcr(ioaddr, i); + } + *buff++ = 0; /* skip bcr30 so as not to hang 79C976 */ + for (i = 31; i < 36; i++) { + *buff++ = a->read_bcr(ioaddr, i); + } + + /* read mii phy registers */ + if (lp->mii) { + int j; + for (j = 0; j < PCNET32_MAX_PHYS; j++) { + if (lp->phymask & (1 << j)) { + for (i = 0; i < PCNET32_REGS_PER_PHY; i++) { + lp->a.write_bcr(ioaddr, 33, + (j << 5) | i); + *buff++ = lp->a.read_bcr(ioaddr, 34); + } + } + } + } + + if (!(csr0 & 0x0004)) { /* If not stopped */ + /* clear SUSPEND (SPND) - CSR5 bit 0 */ + a->write_csr(ioaddr, 5, 0x0000); + } + + spin_unlock_irqrestore(&lp->lock, flags); } static struct ethtool_ops pcnet32_ethtool_ops = { - .get_settings = pcnet32_get_settings, - .set_settings = pcnet32_set_settings, - .get_drvinfo = pcnet32_get_drvinfo, - .get_msglevel = pcnet32_get_msglevel, - .set_msglevel = pcnet32_set_msglevel, - .nway_reset = pcnet32_nway_reset, - .get_link = pcnet32_get_link, - .get_ringparam = pcnet32_get_ringparam, - .set_ringparam = pcnet32_set_ringparam, - .get_tx_csum = ethtool_op_get_tx_csum, - .get_sg = ethtool_op_get_sg, - .get_tso = ethtool_op_get_tso, - .get_strings = pcnet32_get_strings, - .self_test_count = pcnet32_self_test_count, - .self_test = pcnet32_ethtool_test, - .phys_id = pcnet32_phys_id, - .get_regs_len = pcnet32_get_regs_len, - .get_regs = pcnet32_get_regs, - .get_perm_addr = ethtool_op_get_perm_addr, + .get_settings = pcnet32_get_settings, + .set_settings = pcnet32_set_settings, + .get_drvinfo = pcnet32_get_drvinfo, + .get_msglevel = pcnet32_get_msglevel, + .set_msglevel = pcnet32_set_msglevel, + .nway_reset = pcnet32_nway_reset, + .get_link = pcnet32_get_link, + .get_ringparam = pcnet32_get_ringparam, + .set_ringparam = pcnet32_set_ringparam, + .get_tx_csum = ethtool_op_get_tx_csum, + .get_sg = ethtool_op_get_sg, + .get_tso = ethtool_op_get_tso, + .get_strings = pcnet32_get_strings, + .self_test_count = pcnet32_self_test_count, + .self_test = pcnet32_ethtool_test, + .phys_id = pcnet32_phys_id, + .get_regs_len = pcnet32_get_regs_len, + .get_regs = pcnet32_get_regs, + .get_perm_addr = ethtool_op_get_perm_addr, }; /* only probes for non-PCI devices, the rest are handled by * pci_register_driver via pcnet32_probe_pci */ -static void __devinit -pcnet32_probe_vlbus(void) +static void __devinit pcnet32_probe_vlbus(void) { - unsigned int *port, ioaddr; - - /* search for PCnet32 VLB cards at known addresses */ - for (port = pcnet32_portlist; (ioaddr = *port); port++) { - if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_vlbus")) { - /* check if there is really a pcnet chip on that ioaddr */ - if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57)) { - pcnet32_probe1(ioaddr, 0, NULL); - } else { - release_region(ioaddr, PCNET32_TOTAL_SIZE); - } - } - } + unsigned int *port, ioaddr; + + /* search for PCnet32 VLB cards at known addresses */ + for (port = pcnet32_portlist; (ioaddr = *port); port++) { + if (request_region + (ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_vlbus")) { + /* check if there is really a pcnet chip on that ioaddr */ + if ((inb(ioaddr + 14) == 0x57) + && (inb(ioaddr + 15) == 0x57)) { + pcnet32_probe1(ioaddr, 0, NULL); + } else { + release_region(ioaddr, PCNET32_TOTAL_SIZE); + } + } + } } - static int __devinit pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent) { - unsigned long ioaddr; - int err; - - err = pci_enable_device(pdev); - if (err < 0) { - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_ERR PFX "failed to enable device -- err=%d\n", err); - return err; - } - pci_set_master(pdev); + unsigned long ioaddr; + int err; + + err = pci_enable_device(pdev); + if (err < 0) { + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(KERN_ERR PFX + "failed to enable device -- err=%d\n", err); + return err; + } + pci_set_master(pdev); + + ioaddr = pci_resource_start(pdev, 0); + if (!ioaddr) { + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(KERN_ERR PFX + "card has no PCI IO resources, aborting\n"); + return -ENODEV; + } - ioaddr = pci_resource_start (pdev, 0); - if (!ioaddr) { - if (pcnet32_debug & NETIF_MSG_PROBE) - printk (KERN_ERR PFX "card has no PCI IO resources, aborting\n"); - return -ENODEV; - } + if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) { + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(KERN_ERR PFX + "architecture does not support 32bit PCI busmaster DMA\n"); + return -ENODEV; + } + if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci") == + NULL) { + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(KERN_ERR PFX + "io address range already allocated\n"); + return -EBUSY; + } - if (!pci_dma_supported(pdev, PCNET32_DMA_MASK)) { - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_ERR PFX "architecture does not support 32bit PCI busmaster DMA\n"); - return -ENODEV; - } - if (request_region(ioaddr, PCNET32_TOTAL_SIZE, "pcnet32_probe_pci") == NULL) { - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_ERR PFX "io address range already allocated\n"); - return -EBUSY; - } - - err = pcnet32_probe1(ioaddr, 1, pdev); - if (err < 0) { - pci_disable_device(pdev); - } - return err; + err = pcnet32_probe1(ioaddr, 1, pdev); + if (err < 0) { + pci_disable_device(pdev); + } + return err; } - /* pcnet32_probe1 * Called from both pcnet32_probe_vlbus and pcnet_probe_pci. * pdev will be NULL when called from pcnet32_probe_vlbus. @@ -1121,710 +1148,764 @@ pcnet32_probe_pci(struct pci_dev *pdev, const struct pci_device_id *ent) static int __devinit pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) { - struct pcnet32_private *lp; - dma_addr_t lp_dma_addr; - int i, media; - int fdx, mii, fset, dxsuflo; - int chip_version; - char *chipname; - struct net_device *dev; - struct pcnet32_access *a = NULL; - u8 promaddr[6]; - int ret = -ENODEV; - - /* reset the chip */ - pcnet32_wio_reset(ioaddr); - - /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */ - if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && pcnet32_wio_check(ioaddr)) { - a = &pcnet32_wio; - } else { - pcnet32_dwio_reset(ioaddr); - if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { - a = &pcnet32_dwio; - } else - goto err_release_region; - } - - chip_version = a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr,89) << 16); - if ((pcnet32_debug & NETIF_MSG_PROBE) && (pcnet32_debug & NETIF_MSG_HW)) - printk(KERN_INFO " PCnet chip version is %#x.\n", chip_version); - if ((chip_version & 0xfff) != 0x003) { - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_INFO PFX "Unsupported chip version.\n"); - goto err_release_region; - } - - /* initialize variables */ - fdx = mii = fset = dxsuflo = 0; - chip_version = (chip_version >> 12) & 0xffff; - - switch (chip_version) { - case 0x2420: - chipname = "PCnet/PCI 79C970"; /* PCI */ - break; - case 0x2430: - if (shared) - chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */ - else - chipname = "PCnet/32 79C965"; /* 486/VL bus */ - break; - case 0x2621: - chipname = "PCnet/PCI II 79C970A"; /* PCI */ - fdx = 1; - break; - case 0x2623: - chipname = "PCnet/FAST 79C971"; /* PCI */ - fdx = 1; mii = 1; fset = 1; - break; - case 0x2624: - chipname = "PCnet/FAST+ 79C972"; /* PCI */ - fdx = 1; mii = 1; fset = 1; - break; - case 0x2625: - chipname = "PCnet/FAST III 79C973"; /* PCI */ - fdx = 1; mii = 1; - break; - case 0x2626: - chipname = "PCnet/Home 79C978"; /* PCI */ - fdx = 1; + struct pcnet32_private *lp; + dma_addr_t lp_dma_addr; + int i, media; + int fdx, mii, fset, dxsuflo; + int chip_version; + char *chipname; + struct net_device *dev; + struct pcnet32_access *a = NULL; + u8 promaddr[6]; + int ret = -ENODEV; + + /* reset the chip */ + pcnet32_wio_reset(ioaddr); + + /* NOTE: 16-bit check is first, otherwise some older PCnet chips fail */ + if (pcnet32_wio_read_csr(ioaddr, 0) == 4 && pcnet32_wio_check(ioaddr)) { + a = &pcnet32_wio; + } else { + pcnet32_dwio_reset(ioaddr); + if (pcnet32_dwio_read_csr(ioaddr, 0) == 4 + && pcnet32_dwio_check(ioaddr)) { + a = &pcnet32_dwio; + } else + goto err_release_region; + } + + chip_version = + a->read_csr(ioaddr, 88) | (a->read_csr(ioaddr, 89) << 16); + if ((pcnet32_debug & NETIF_MSG_PROBE) && (pcnet32_debug & NETIF_MSG_HW)) + printk(KERN_INFO " PCnet chip version is %#x.\n", + chip_version); + if ((chip_version & 0xfff) != 0x003) { + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(KERN_INFO PFX "Unsupported chip version.\n"); + goto err_release_region; + } + + /* initialize variables */ + fdx = mii = fset = dxsuflo = 0; + chip_version = (chip_version >> 12) & 0xffff; + + switch (chip_version) { + case 0x2420: + chipname = "PCnet/PCI 79C970"; /* PCI */ + break; + case 0x2430: + if (shared) + chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */ + else + chipname = "PCnet/32 79C965"; /* 486/VL bus */ + break; + case 0x2621: + chipname = "PCnet/PCI II 79C970A"; /* PCI */ + fdx = 1; + break; + case 0x2623: + chipname = "PCnet/FAST 79C971"; /* PCI */ + fdx = 1; + mii = 1; + fset = 1; + break; + case 0x2624: + chipname = "PCnet/FAST+ 79C972"; /* PCI */ + fdx = 1; + mii = 1; + fset = 1; + break; + case 0x2625: + chipname = "PCnet/FAST III 79C973"; /* PCI */ + fdx = 1; + mii = 1; + break; + case 0x2626: + chipname = "PCnet/Home 79C978"; /* PCI */ + fdx = 1; + /* + * This is based on specs published at www.amd.com. This section + * assumes that a card with a 79C978 wants to go into standard + * ethernet mode. The 79C978 can also go into 1Mb HomePNA mode, + * and the module option homepna=1 can select this instead. + */ + media = a->read_bcr(ioaddr, 49); + media &= ~3; /* default to 10Mb ethernet */ + if (cards_found < MAX_UNITS && homepna[cards_found]) + media |= 1; /* switch to home wiring mode */ + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(KERN_DEBUG PFX "media set to %sMbit mode.\n", + (media & 1) ? "1" : "10"); + a->write_bcr(ioaddr, 49, media); + break; + case 0x2627: + chipname = "PCnet/FAST III 79C975"; /* PCI */ + fdx = 1; + mii = 1; + break; + case 0x2628: + chipname = "PCnet/PRO 79C976"; + fdx = 1; + mii = 1; + break; + default: + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(KERN_INFO PFX + "PCnet version %#x, no PCnet32 chip.\n", + chip_version); + goto err_release_region; + } + /* - * This is based on specs published at www.amd.com. This section - * assumes that a card with a 79C978 wants to go into standard - * ethernet mode. The 79C978 can also go into 1Mb HomePNA mode, - * and the module option homepna=1 can select this instead. + * On selected chips turn on the BCR18:NOUFLO bit. This stops transmit + * starting until the packet is loaded. Strike one for reliability, lose + * one for latency - although on PCI this isnt a big loss. Older chips + * have FIFO's smaller than a packet, so you can't do this. + * Turn on BCR18:BurstRdEn and BCR18:BurstWrEn. */ - media = a->read_bcr(ioaddr, 49); - media &= ~3; /* default to 10Mb ethernet */ - if (cards_found < MAX_UNITS && homepna[cards_found]) - media |= 1; /* switch to home wiring mode */ - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_DEBUG PFX "media set to %sMbit mode.\n", - (media & 1) ? "1" : "10"); - a->write_bcr(ioaddr, 49, media); - break; - case 0x2627: - chipname = "PCnet/FAST III 79C975"; /* PCI */ - fdx = 1; mii = 1; - break; - case 0x2628: - chipname = "PCnet/PRO 79C976"; - fdx = 1; mii = 1; - break; - default: - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_INFO PFX "PCnet version %#x, no PCnet32 chip.\n", - chip_version); - goto err_release_region; - } - - /* - * On selected chips turn on the BCR18:NOUFLO bit. This stops transmit - * starting until the packet is loaded. Strike one for reliability, lose - * one for latency - although on PCI this isnt a big loss. Older chips - * have FIFO's smaller than a packet, so you can't do this. - * Turn on BCR18:BurstRdEn and BCR18:BurstWrEn. - */ - - if (fset) { - a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0860)); - a->write_csr(ioaddr, 80, (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00); - dxsuflo = 1; - } - - dev = alloc_etherdev(0); - if (!dev) { + + if (fset) { + a->write_bcr(ioaddr, 18, (a->read_bcr(ioaddr, 18) | 0x0860)); + a->write_csr(ioaddr, 80, + (a->read_csr(ioaddr, 80) & 0x0C00) | 0x0c00); + dxsuflo = 1; + } + + dev = alloc_etherdev(0); + if (!dev) { + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(KERN_ERR PFX "Memory allocation failed.\n"); + ret = -ENOMEM; + goto err_release_region; + } + SET_NETDEV_DEV(dev, &pdev->dev); + if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_ERR PFX "Memory allocation failed.\n"); - ret = -ENOMEM; - goto err_release_region; - } - SET_NETDEV_DEV(dev, &pdev->dev); - - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr); - - /* In most chips, after a chip reset, the ethernet address is read from the - * station address PROM at the base address and programmed into the - * "Physical Address Registers" CSR12-14. - * As a precautionary measure, we read the PROM values and complain if - * they disagree with the CSRs. Either way, we use the CSR values, and - * double check that they are valid. - */ - for (i = 0; i < 3; i++) { - unsigned int val; - val = a->read_csr(ioaddr, i+12) & 0x0ffff; - /* There may be endianness issues here. */ - dev->dev_addr[2*i] = val & 0x0ff; - dev->dev_addr[2*i+1] = (val >> 8) & 0x0ff; - } - - /* read PROM address and compare with CSR address */ - for (i = 0; i < 6; i++) - promaddr[i] = inb(ioaddr + i); - - if (memcmp(promaddr, dev->dev_addr, 6) - || !is_valid_ether_addr(dev->dev_addr)) { - if (is_valid_ether_addr(promaddr)) { - if (pcnet32_debug & NETIF_MSG_PROBE) { - printk(" warning: CSR address invalid,\n"); - printk(KERN_INFO " using instead PROM address of"); - } - memcpy(dev->dev_addr, promaddr, 6); - } - } - memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - - /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */ - if (!is_valid_ether_addr(dev->perm_addr)) - memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); - - if (pcnet32_debug & NETIF_MSG_PROBE) { + printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr); + + /* In most chips, after a chip reset, the ethernet address is read from the + * station address PROM at the base address and programmed into the + * "Physical Address Registers" CSR12-14. + * As a precautionary measure, we read the PROM values and complain if + * they disagree with the CSRs. Either way, we use the CSR values, and + * double check that they are valid. + */ + for (i = 0; i < 3; i++) { + unsigned int val; + val = a->read_csr(ioaddr, i + 12) & 0x0ffff; + /* There may be endianness issues here. */ + dev->dev_addr[2 * i] = val & 0x0ff; + dev->dev_addr[2 * i + 1] = (val >> 8) & 0x0ff; + } + + /* read PROM address and compare with CSR address */ for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i]); - - /* Version 0x2623 and 0x2624 */ - if (((chip_version + 1) & 0xfffe) == 0x2624) { - i = a->read_csr(ioaddr, 80) & 0x0C00; /* Check tx_start_pt */ - printk("\n" KERN_INFO " tx_start_pt(0x%04x):",i); - switch(i>>10) { - case 0: printk(" 20 bytes,"); break; - case 1: printk(" 64 bytes,"); break; - case 2: printk(" 128 bytes,"); break; - case 3: printk("~220 bytes,"); break; - } - i = a->read_bcr(ioaddr, 18); /* Check Burst/Bus control */ - printk(" BCR18(%x):",i&0xffff); - if (i & (1<<5)) printk("BurstWrEn "); - if (i & (1<<6)) printk("BurstRdEn "); - if (i & (1<<7)) printk("DWordIO "); - if (i & (1<<11)) printk("NoUFlow "); - i = a->read_bcr(ioaddr, 25); - printk("\n" KERN_INFO " SRAMSIZE=0x%04x,",i<<8); - i = a->read_bcr(ioaddr, 26); - printk(" SRAM_BND=0x%04x,",i<<8); - i = a->read_bcr(ioaddr, 27); - if (i & (1<<14)) printk("LowLatRx"); - } - } - - dev->base_addr = ioaddr; - /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ - if ((lp = pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) { - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_ERR PFX "Consistent memory allocation failed.\n"); - ret = -ENOMEM; - goto err_free_netdev; - } - - memset(lp, 0, sizeof(*lp)); - lp->dma_addr = lp_dma_addr; - lp->pci_dev = pdev; - - spin_lock_init(&lp->lock); - - SET_MODULE_OWNER(dev); - SET_NETDEV_DEV(dev, &pdev->dev); - dev->priv = lp; - lp->name = chipname; - lp->shared_irq = shared; - lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */ - lp->rx_ring_size = RX_RING_SIZE; /* default rx ring size */ - lp->tx_mod_mask = lp->tx_ring_size - 1; - lp->rx_mod_mask = lp->rx_ring_size - 1; - lp->tx_len_bits = (PCNET32_LOG_TX_BUFFERS << 12); - lp->rx_len_bits = (PCNET32_LOG_RX_BUFFERS << 4); - lp->mii_if.full_duplex = fdx; - lp->mii_if.phy_id_mask = 0x1f; - lp->mii_if.reg_num_mask = 0x1f; - lp->dxsuflo = dxsuflo; - lp->mii = mii; - lp->msg_enable = pcnet32_debug; - if ((cards_found >= MAX_UNITS) || (options[cards_found] > sizeof(options_mapping))) - lp->options = PCNET32_PORT_ASEL; - else - lp->options = options_mapping[options[cards_found]]; - lp->mii_if.dev = dev; - lp->mii_if.mdio_read = mdio_read; - lp->mii_if.mdio_write = mdio_write; - - if (fdx && !(lp->options & PCNET32_PORT_ASEL) && - ((cards_found>=MAX_UNITS) || full_duplex[cards_found])) - lp->options |= PCNET32_PORT_FD; - - if (!a) { - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_ERR PFX "No access methods\n"); - ret = -ENODEV; - goto err_free_consistent; - } - lp->a = *a; - - /* prior to register_netdev, dev->name is not yet correct */ - if (pcnet32_alloc_ring(dev, pci_name(lp->pci_dev))) { - ret = -ENOMEM; - goto err_free_ring; - } - /* detect special T1/E1 WAN card by checking for MAC address */ - if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 + promaddr[i] = inb(ioaddr + i); + + if (memcmp(promaddr, dev->dev_addr, 6) + || !is_valid_ether_addr(dev->dev_addr)) { + if (is_valid_ether_addr(promaddr)) { + if (pcnet32_debug & NETIF_MSG_PROBE) { + printk(" warning: CSR address invalid,\n"); + printk(KERN_INFO + " using instead PROM address of"); + } + memcpy(dev->dev_addr, promaddr, 6); + } + } + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + + /* if the ethernet address is not valid, force to 00:00:00:00:00:00 */ + if (!is_valid_ether_addr(dev->perm_addr)) + memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); + + if (pcnet32_debug & NETIF_MSG_PROBE) { + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i]); + + /* Version 0x2623 and 0x2624 */ + if (((chip_version + 1) & 0xfffe) == 0x2624) { + i = a->read_csr(ioaddr, 80) & 0x0C00; /* Check tx_start_pt */ + printk("\n" KERN_INFO " tx_start_pt(0x%04x):", i); + switch (i >> 10) { + case 0: + printk(" 20 bytes,"); + break; + case 1: + printk(" 64 bytes,"); + break; + case 2: + printk(" 128 bytes,"); + break; + case 3: + printk("~220 bytes,"); + break; + } + i = a->read_bcr(ioaddr, 18); /* Check Burst/Bus control */ + printk(" BCR18(%x):", i & 0xffff); + if (i & (1 << 5)) + printk("BurstWrEn "); + if (i & (1 << 6)) + printk("BurstRdEn "); + if (i & (1 << 7)) + printk("DWordIO "); + if (i & (1 << 11)) + printk("NoUFlow "); + i = a->read_bcr(ioaddr, 25); + printk("\n" KERN_INFO " SRAMSIZE=0x%04x,", i << 8); + i = a->read_bcr(ioaddr, 26); + printk(" SRAM_BND=0x%04x,", i << 8); + i = a->read_bcr(ioaddr, 27); + if (i & (1 << 14)) + printk("LowLatRx"); + } + } + + dev->base_addr = ioaddr; + /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ + if ((lp = + pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) { + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(KERN_ERR PFX + "Consistent memory allocation failed.\n"); + ret = -ENOMEM; + goto err_free_netdev; + } + + memset(lp, 0, sizeof(*lp)); + lp->dma_addr = lp_dma_addr; + lp->pci_dev = pdev; + + spin_lock_init(&lp->lock); + + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); + dev->priv = lp; + lp->name = chipname; + lp->shared_irq = shared; + lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */ + lp->rx_ring_size = RX_RING_SIZE; /* default rx ring size */ + lp->tx_mod_mask = lp->tx_ring_size - 1; + lp->rx_mod_mask = lp->rx_ring_size - 1; + lp->tx_len_bits = (PCNET32_LOG_TX_BUFFERS << 12); + lp->rx_len_bits = (PCNET32_LOG_RX_BUFFERS << 4); + lp->mii_if.full_duplex = fdx; + lp->mii_if.phy_id_mask = 0x1f; + lp->mii_if.reg_num_mask = 0x1f; + lp->dxsuflo = dxsuflo; + lp->mii = mii; + lp->msg_enable = pcnet32_debug; + if ((cards_found >= MAX_UNITS) + || (options[cards_found] > sizeof(options_mapping))) + lp->options = PCNET32_PORT_ASEL; + else + lp->options = options_mapping[options[cards_found]]; + lp->mii_if.dev = dev; + lp->mii_if.mdio_read = mdio_read; + lp->mii_if.mdio_write = mdio_write; + + if (fdx && !(lp->options & PCNET32_PORT_ASEL) && + ((cards_found >= MAX_UNITS) || full_duplex[cards_found])) + lp->options |= PCNET32_PORT_FD; + + if (!a) { + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(KERN_ERR PFX "No access methods\n"); + ret = -ENODEV; + goto err_free_consistent; + } + lp->a = *a; + + /* prior to register_netdev, dev->name is not yet correct */ + if (pcnet32_alloc_ring(dev, pci_name(lp->pci_dev))) { + ret = -ENOMEM; + goto err_free_ring; + } + /* detect special T1/E1 WAN card by checking for MAC address */ + if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && dev->dev_addr[2] == 0x75) - lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; - - lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ - lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); - for (i = 0; i < 6; i++) - lp->init_block.phys_addr[i] = dev->dev_addr[i]; - lp->init_block.filter[0] = 0x00000000; - lp->init_block.filter[1] = 0x00000000; - lp->init_block.rx_ring = (u32)le32_to_cpu(lp->rx_ring_dma_addr); - lp->init_block.tx_ring = (u32)le32_to_cpu(lp->tx_ring_dma_addr); - - /* switch pcnet32 to 32bit mode */ - a->write_bcr(ioaddr, 20, 2); - - a->write_csr(ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, - init_block)) & 0xffff); - a->write_csr(ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, - init_block)) >> 16); - - if (pdev) { /* use the IRQ provided by PCI */ - dev->irq = pdev->irq; - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(" assigned IRQ %d.\n", dev->irq); - } else { - unsigned long irq_mask = probe_irq_on(); + lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; - /* - * To auto-IRQ we enable the initialization-done and DMA error - * interrupts. For ISA boards we get a DMA error, but VLB and PCI - * boards will work. - */ - /* Trigger an initialization just for the interrupt. */ - a->write_csr (ioaddr, 0, 0x41); - mdelay (1); + lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ + lp->init_block.tlen_rlen = + le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); + for (i = 0; i < 6; i++) + lp->init_block.phys_addr[i] = dev->dev_addr[i]; + lp->init_block.filter[0] = 0x00000000; + lp->init_block.filter[1] = 0x00000000; + lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); + lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); + + /* switch pcnet32 to 32bit mode */ + a->write_bcr(ioaddr, 20, 2); + + a->write_csr(ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, + init_block)) & 0xffff); + a->write_csr(ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, + init_block)) >> 16); + + if (pdev) { /* use the IRQ provided by PCI */ + dev->irq = pdev->irq; + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(" assigned IRQ %d.\n", dev->irq); + } else { + unsigned long irq_mask = probe_irq_on(); + + /* + * To auto-IRQ we enable the initialization-done and DMA error + * interrupts. For ISA boards we get a DMA error, but VLB and PCI + * boards will work. + */ + /* Trigger an initialization just for the interrupt. */ + a->write_csr(ioaddr, 0, 0x41); + mdelay(1); + + dev->irq = probe_irq_off(irq_mask); + if (!dev->irq) { + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(", failed to detect IRQ line.\n"); + ret = -ENODEV; + goto err_free_ring; + } + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(", probed IRQ %d.\n", dev->irq); + } - dev->irq = probe_irq_off (irq_mask); - if (!dev->irq) { - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(", failed to detect IRQ line.\n"); - ret = -ENODEV; - goto err_free_ring; + /* Set the mii phy_id so that we can query the link state */ + if (lp->mii) { + /* lp->phycount and lp->phymask are set to 0 by memset above */ + + lp->mii_if.phy_id = ((lp->a.read_bcr(ioaddr, 33)) >> 5) & 0x1f; + /* scan for PHYs */ + for (i = 0; i < PCNET32_MAX_PHYS; i++) { + unsigned short id1, id2; + + id1 = mdio_read(dev, i, MII_PHYSID1); + if (id1 == 0xffff) + continue; + id2 = mdio_read(dev, i, MII_PHYSID2); + if (id2 == 0xffff) + continue; + if (i == 31 && ((chip_version + 1) & 0xfffe) == 0x2624) + continue; /* 79C971 & 79C972 have phantom phy at id 31 */ + lp->phycount++; + lp->phymask |= (1 << i); + lp->mii_if.phy_id = i; + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(KERN_INFO PFX + "Found PHY %04x:%04x at address %d.\n", + id1, id2, i); + } + lp->a.write_bcr(ioaddr, 33, (lp->mii_if.phy_id) << 5); + if (lp->phycount > 1) { + lp->options |= PCNET32_PORT_MII; + } } - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(", probed IRQ %d.\n", dev->irq); - } - - /* Set the mii phy_id so that we can query the link state */ - if (lp->mii) { - /* lp->phycount and lp->phymask are set to 0 by memset above */ - - lp->mii_if.phy_id = ((lp->a.read_bcr (ioaddr, 33)) >> 5) & 0x1f; - /* scan for PHYs */ - for (i=0; iphycount++; - lp->phymask |= (1 << i); - lp->mii_if.phy_id = i; - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_INFO PFX "Found PHY %04x:%04x at address %d.\n", - id1, id2, i); - } - lp->a.write_bcr(ioaddr, 33, (lp->mii_if.phy_id) << 5); - if (lp->phycount > 1) { - lp->options |= PCNET32_PORT_MII; - } - } - - init_timer (&lp->watchdog_timer); - lp->watchdog_timer.data = (unsigned long) dev; - lp->watchdog_timer.function = (void *) &pcnet32_watchdog; - - /* The PCNET32-specific entries in the device structure. */ - dev->open = &pcnet32_open; - dev->hard_start_xmit = &pcnet32_start_xmit; - dev->stop = &pcnet32_close; - dev->get_stats = &pcnet32_get_stats; - dev->set_multicast_list = &pcnet32_set_multicast_list; - dev->do_ioctl = &pcnet32_ioctl; - dev->ethtool_ops = &pcnet32_ethtool_ops; - dev->tx_timeout = pcnet32_tx_timeout; - dev->watchdog_timeo = (5*HZ); + + init_timer(&lp->watchdog_timer); + lp->watchdog_timer.data = (unsigned long)dev; + lp->watchdog_timer.function = (void *)&pcnet32_watchdog; + + /* The PCNET32-specific entries in the device structure. */ + dev->open = &pcnet32_open; + dev->hard_start_xmit = &pcnet32_start_xmit; + dev->stop = &pcnet32_close; + dev->get_stats = &pcnet32_get_stats; + dev->set_multicast_list = &pcnet32_set_multicast_list; + dev->do_ioctl = &pcnet32_ioctl; + dev->ethtool_ops = &pcnet32_ethtool_ops; + dev->tx_timeout = pcnet32_tx_timeout; + dev->watchdog_timeo = (5 * HZ); #ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = pcnet32_poll_controller; + dev->poll_controller = pcnet32_poll_controller; #endif - /* Fill in the generic fields of the device structure. */ - if (register_netdev(dev)) - goto err_free_ring; - - if (pdev) { - pci_set_drvdata(pdev, dev); - } else { - lp->next = pcnet32_dev; - pcnet32_dev = dev; - } - - if (pcnet32_debug & NETIF_MSG_PROBE) - printk(KERN_INFO "%s: registered as %s\n", dev->name, lp->name); - cards_found++; - - /* enable LED writes */ - a->write_bcr(ioaddr, 2, a->read_bcr(ioaddr, 2) | 0x1000); - - return 0; - -err_free_ring: - pcnet32_free_ring(dev); -err_free_consistent: - pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); -err_free_netdev: - free_netdev(dev); -err_release_region: - release_region(ioaddr, PCNET32_TOTAL_SIZE); - return ret; -} + /* Fill in the generic fields of the device structure. */ + if (register_netdev(dev)) + goto err_free_ring; + + if (pdev) { + pci_set_drvdata(pdev, dev); + } else { + lp->next = pcnet32_dev; + pcnet32_dev = dev; + } + + if (pcnet32_debug & NETIF_MSG_PROBE) + printk(KERN_INFO "%s: registered as %s\n", dev->name, lp->name); + cards_found++; + + /* enable LED writes */ + a->write_bcr(ioaddr, 2, a->read_bcr(ioaddr, 2) | 0x1000); + return 0; + + err_free_ring: + pcnet32_free_ring(dev); + err_free_consistent: + pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); + err_free_netdev: + free_netdev(dev); + err_release_region: + release_region(ioaddr, PCNET32_TOTAL_SIZE); + return ret; +} /* if any allocation fails, caller must also call pcnet32_free_ring */ static int pcnet32_alloc_ring(struct net_device *dev, char *name) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = dev->priv; - lp->tx_ring = pci_alloc_consistent(lp->pci_dev, - sizeof(struct pcnet32_tx_head) * lp->tx_ring_size, - &lp->tx_ring_dma_addr); - if (lp->tx_ring == NULL) { - if (pcnet32_debug & NETIF_MSG_DRV) - printk("\n" KERN_ERR PFX "%s: Consistent memory allocation failed.\n", - name); - return -ENOMEM; - } - - lp->rx_ring = pci_alloc_consistent(lp->pci_dev, - sizeof(struct pcnet32_rx_head) * lp->rx_ring_size, - &lp->rx_ring_dma_addr); - if (lp->rx_ring == NULL) { - if (pcnet32_debug & NETIF_MSG_DRV) - printk("\n" KERN_ERR PFX "%s: Consistent memory allocation failed.\n", - name); - return -ENOMEM; - } - - lp->tx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->tx_ring_size, - GFP_ATOMIC); - if (!lp->tx_dma_addr) { - if (pcnet32_debug & NETIF_MSG_DRV) - printk("\n" KERN_ERR PFX "%s: Memory allocation failed.\n", name); - return -ENOMEM; - } - memset(lp->tx_dma_addr, 0, sizeof(dma_addr_t) * lp->tx_ring_size); - - lp->rx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->rx_ring_size, - GFP_ATOMIC); - if (!lp->rx_dma_addr) { - if (pcnet32_debug & NETIF_MSG_DRV) - printk("\n" KERN_ERR PFX "%s: Memory allocation failed.\n", name); - return -ENOMEM; - } - memset(lp->rx_dma_addr, 0, sizeof(dma_addr_t) * lp->rx_ring_size); - - lp->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->tx_ring_size, - GFP_ATOMIC); - if (!lp->tx_skbuff) { - if (pcnet32_debug & NETIF_MSG_DRV) - printk("\n" KERN_ERR PFX "%s: Memory allocation failed.\n", name); - return -ENOMEM; - } - memset(lp->tx_skbuff, 0, sizeof(struct sk_buff *) * lp->tx_ring_size); - - lp->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->rx_ring_size, - GFP_ATOMIC); - if (!lp->rx_skbuff) { - if (pcnet32_debug & NETIF_MSG_DRV) - printk("\n" KERN_ERR PFX "%s: Memory allocation failed.\n", name); - return -ENOMEM; - } - memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size); + lp->tx_ring = pci_alloc_consistent(lp->pci_dev, + sizeof(struct pcnet32_tx_head) * + lp->tx_ring_size, + &lp->tx_ring_dma_addr); + if (lp->tx_ring == NULL) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk("\n" KERN_ERR PFX + "%s: Consistent memory allocation failed.\n", + name); + return -ENOMEM; + } - return 0; -} + lp->rx_ring = pci_alloc_consistent(lp->pci_dev, + sizeof(struct pcnet32_rx_head) * + lp->rx_ring_size, + &lp->rx_ring_dma_addr); + if (lp->rx_ring == NULL) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk("\n" KERN_ERR PFX + "%s: Consistent memory allocation failed.\n", + name); + return -ENOMEM; + } + lp->tx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->tx_ring_size, + GFP_ATOMIC); + if (!lp->tx_dma_addr) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk("\n" KERN_ERR PFX + "%s: Memory allocation failed.\n", name); + return -ENOMEM; + } + memset(lp->tx_dma_addr, 0, sizeof(dma_addr_t) * lp->tx_ring_size); + + lp->rx_dma_addr = kmalloc(sizeof(dma_addr_t) * lp->rx_ring_size, + GFP_ATOMIC); + if (!lp->rx_dma_addr) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk("\n" KERN_ERR PFX + "%s: Memory allocation failed.\n", name); + return -ENOMEM; + } + memset(lp->rx_dma_addr, 0, sizeof(dma_addr_t) * lp->rx_ring_size); + + lp->tx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->tx_ring_size, + GFP_ATOMIC); + if (!lp->tx_skbuff) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk("\n" KERN_ERR PFX + "%s: Memory allocation failed.\n", name); + return -ENOMEM; + } + memset(lp->tx_skbuff, 0, sizeof(struct sk_buff *) * lp->tx_ring_size); + + lp->rx_skbuff = kmalloc(sizeof(struct sk_buff *) * lp->rx_ring_size, + GFP_ATOMIC); + if (!lp->rx_skbuff) { + if (pcnet32_debug & NETIF_MSG_DRV) + printk("\n" KERN_ERR PFX + "%s: Memory allocation failed.\n", name); + return -ENOMEM; + } + memset(lp->rx_skbuff, 0, sizeof(struct sk_buff *) * lp->rx_ring_size); + + return 0; +} static void pcnet32_free_ring(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; + struct pcnet32_private *lp = dev->priv; - kfree(lp->tx_skbuff); - lp->tx_skbuff = NULL; + kfree(lp->tx_skbuff); + lp->tx_skbuff = NULL; - kfree(lp->rx_skbuff); - lp->rx_skbuff = NULL; + kfree(lp->rx_skbuff); + lp->rx_skbuff = NULL; - kfree(lp->tx_dma_addr); - lp->tx_dma_addr = NULL; + kfree(lp->tx_dma_addr); + lp->tx_dma_addr = NULL; - kfree(lp->rx_dma_addr); - lp->rx_dma_addr = NULL; + kfree(lp->rx_dma_addr); + lp->rx_dma_addr = NULL; - if (lp->tx_ring) { - pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_tx_head) * lp->tx_ring_size, - lp->tx_ring, lp->tx_ring_dma_addr); - lp->tx_ring = NULL; - } + if (lp->tx_ring) { + pci_free_consistent(lp->pci_dev, + sizeof(struct pcnet32_tx_head) * + lp->tx_ring_size, lp->tx_ring, + lp->tx_ring_dma_addr); + lp->tx_ring = NULL; + } - if (lp->rx_ring) { - pci_free_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * lp->rx_ring_size, - lp->rx_ring, lp->rx_ring_dma_addr); - lp->rx_ring = NULL; - } + if (lp->rx_ring) { + pci_free_consistent(lp->pci_dev, + sizeof(struct pcnet32_rx_head) * + lp->rx_ring_size, lp->rx_ring, + lp->rx_ring_dma_addr); + lp->rx_ring = NULL; + } } - -static int -pcnet32_open(struct net_device *dev) +static int pcnet32_open(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - unsigned long ioaddr = dev->base_addr; - u16 val; - int i; - int rc; - unsigned long flags; - - if (request_irq(dev->irq, &pcnet32_interrupt, - lp->shared_irq ? SA_SHIRQ : 0, dev->name, (void *)dev)) { - return -EAGAIN; - } - - spin_lock_irqsave(&lp->lock, flags); - /* Check for a valid station address */ - if (!is_valid_ether_addr(dev->dev_addr)) { - rc = -EINVAL; - goto err_free_irq; - } - - /* Reset the PCNET32 */ - lp->a.reset (ioaddr); - - /* switch pcnet32 to 32bit mode */ - lp->a.write_bcr (ioaddr, 20, 2); - - if (netif_msg_ifup(lp)) - printk(KERN_DEBUG "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", - dev->name, dev->irq, - (u32) (lp->tx_ring_dma_addr), - (u32) (lp->rx_ring_dma_addr), - (u32) (lp->dma_addr + offsetof(struct pcnet32_private, init_block))); - - /* set/reset autoselect bit */ - val = lp->a.read_bcr (ioaddr, 2) & ~2; - if (lp->options & PCNET32_PORT_ASEL) - val |= 2; - lp->a.write_bcr (ioaddr, 2, val); - - /* handle full duplex setting */ - if (lp->mii_if.full_duplex) { - val = lp->a.read_bcr (ioaddr, 9) & ~3; - if (lp->options & PCNET32_PORT_FD) { - val |= 1; - if (lp->options == (PCNET32_PORT_FD | PCNET32_PORT_AUI)) + struct pcnet32_private *lp = dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 val; + int i; + int rc; + unsigned long flags; + + if (request_irq(dev->irq, &pcnet32_interrupt, + lp->shared_irq ? SA_SHIRQ : 0, dev->name, + (void *)dev)) { + return -EAGAIN; + } + + spin_lock_irqsave(&lp->lock, flags); + /* Check for a valid station address */ + if (!is_valid_ether_addr(dev->dev_addr)) { + rc = -EINVAL; + goto err_free_irq; + } + + /* Reset the PCNET32 */ + lp->a.reset(ioaddr); + + /* switch pcnet32 to 32bit mode */ + lp->a.write_bcr(ioaddr, 20, 2); + + if (netif_msg_ifup(lp)) + printk(KERN_DEBUG + "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", + dev->name, dev->irq, (u32) (lp->tx_ring_dma_addr), + (u32) (lp->rx_ring_dma_addr), + (u32) (lp->dma_addr + + offsetof(struct pcnet32_private, init_block))); + + /* set/reset autoselect bit */ + val = lp->a.read_bcr(ioaddr, 2) & ~2; + if (lp->options & PCNET32_PORT_ASEL) val |= 2; - } else if (lp->options & PCNET32_PORT_ASEL) { - /* workaround of xSeries250, turn on for 79C975 only */ - i = ((lp->a.read_csr(ioaddr, 88) | - (lp->a.read_csr(ioaddr,89) << 16)) >> 12) & 0xffff; - if (i == 0x2627) - val |= 3; - } - lp->a.write_bcr (ioaddr, 9, val); - } - - /* set/reset GPSI bit in test register */ - val = lp->a.read_csr (ioaddr, 124) & ~0x10; - if ((lp->options & PCNET32_PORT_PORTSEL) == PCNET32_PORT_GPSI) - val |= 0x10; - lp->a.write_csr (ioaddr, 124, val); - - /* Allied Telesyn AT 2700/2701 FX are 100Mbit only and do not negotiate */ - if (lp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_AT && + lp->a.write_bcr(ioaddr, 2, val); + + /* handle full duplex setting */ + if (lp->mii_if.full_duplex) { + val = lp->a.read_bcr(ioaddr, 9) & ~3; + if (lp->options & PCNET32_PORT_FD) { + val |= 1; + if (lp->options == (PCNET32_PORT_FD | PCNET32_PORT_AUI)) + val |= 2; + } else if (lp->options & PCNET32_PORT_ASEL) { + /* workaround of xSeries250, turn on for 79C975 only */ + i = ((lp->a.read_csr(ioaddr, 88) | + (lp->a. + read_csr(ioaddr, 89) << 16)) >> 12) & 0xffff; + if (i == 0x2627) + val |= 3; + } + lp->a.write_bcr(ioaddr, 9, val); + } + + /* set/reset GPSI bit in test register */ + val = lp->a.read_csr(ioaddr, 124) & ~0x10; + if ((lp->options & PCNET32_PORT_PORTSEL) == PCNET32_PORT_GPSI) + val |= 0x10; + lp->a.write_csr(ioaddr, 124, val); + + /* Allied Telesyn AT 2700/2701 FX are 100Mbit only and do not negotiate */ + if (lp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_AT && (lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2700FX || lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2701FX)) { - if (lp->options & PCNET32_PORT_ASEL) { - lp->options = PCNET32_PORT_FD | PCNET32_PORT_100; - if (netif_msg_link(lp)) - printk(KERN_DEBUG "%s: Setting 100Mb-Full Duplex.\n", - dev->name); - } - } - if (lp->phycount < 2) { - /* - * 24 Jun 2004 according AMD, in order to change the PHY, - * DANAS (or DISPM for 79C976) must be set; then select the speed, - * duplex, and/or enable auto negotiation, and clear DANAS - */ - if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) { - lp->a.write_bcr(ioaddr, 32, - lp->a.read_bcr(ioaddr, 32) | 0x0080); - /* disable Auto Negotiation, set 10Mpbs, HD */ - val = lp->a.read_bcr(ioaddr, 32) & ~0xb8; - if (lp->options & PCNET32_PORT_FD) - val |= 0x10; - if (lp->options & PCNET32_PORT_100) - val |= 0x08; - lp->a.write_bcr (ioaddr, 32, val); - } else { - if (lp->options & PCNET32_PORT_ASEL) { - lp->a.write_bcr(ioaddr, 32, - lp->a.read_bcr(ioaddr, 32) | 0x0080); - /* enable auto negotiate, setup, disable fd */ - val = lp->a.read_bcr(ioaddr, 32) & ~0x98; - val |= 0x20; - lp->a.write_bcr(ioaddr, 32, val); - } - } - } else { - int first_phy = -1; - u16 bmcr; - u32 bcr9; - struct ethtool_cmd ecmd; - - /* - * There is really no good other way to handle multiple PHYs - * other than turning off all automatics - */ - val = lp->a.read_bcr(ioaddr, 2); - lp->a.write_bcr(ioaddr, 2, val & ~2); - val = lp->a.read_bcr(ioaddr, 32); - lp->a.write_bcr(ioaddr, 32, val & ~(1 << 7)); /* stop MII manager */ - - if (!(lp->options & PCNET32_PORT_ASEL)) { - /* setup ecmd */ - ecmd.port = PORT_MII; - ecmd.transceiver = XCVR_INTERNAL; - ecmd.autoneg = AUTONEG_DISABLE; - ecmd.speed = lp->options & PCNET32_PORT_100 ? SPEED_100 : SPEED_10; - bcr9 = lp->a.read_bcr(ioaddr, 9); - - if (lp->options & PCNET32_PORT_FD) { - ecmd.duplex = DUPLEX_FULL; - bcr9 |= (1 << 0); - } else { - ecmd.duplex = DUPLEX_HALF; - bcr9 |= ~(1 << 0); - } - lp->a.write_bcr(ioaddr, 9, bcr9); - } - - for (i=0; iphymask & (1 << i)) { - /* isolate all but the first PHY */ - bmcr = mdio_read(dev, i, MII_BMCR); - if (first_phy == -1) { - first_phy = i; - mdio_write(dev, i, MII_BMCR, bmcr & ~BMCR_ISOLATE); - } else { - mdio_write(dev, i, MII_BMCR, bmcr | BMCR_ISOLATE); - } - /* use mii_ethtool_sset to setup PHY */ - lp->mii_if.phy_id = i; - ecmd.phy_address = i; if (lp->options & PCNET32_PORT_ASEL) { - mii_ethtool_gset(&lp->mii_if, &ecmd); - ecmd.autoneg = AUTONEG_ENABLE; + lp->options = PCNET32_PORT_FD | PCNET32_PORT_100; + if (netif_msg_link(lp)) + printk(KERN_DEBUG + "%s: Setting 100Mb-Full Duplex.\n", + dev->name); + } + } + if (lp->phycount < 2) { + /* + * 24 Jun 2004 according AMD, in order to change the PHY, + * DANAS (or DISPM for 79C976) must be set; then select the speed, + * duplex, and/or enable auto negotiation, and clear DANAS + */ + if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) { + lp->a.write_bcr(ioaddr, 32, + lp->a.read_bcr(ioaddr, 32) | 0x0080); + /* disable Auto Negotiation, set 10Mpbs, HD */ + val = lp->a.read_bcr(ioaddr, 32) & ~0xb8; + if (lp->options & PCNET32_PORT_FD) + val |= 0x10; + if (lp->options & PCNET32_PORT_100) + val |= 0x08; + lp->a.write_bcr(ioaddr, 32, val); + } else { + if (lp->options & PCNET32_PORT_ASEL) { + lp->a.write_bcr(ioaddr, 32, + lp->a.read_bcr(ioaddr, + 32) | 0x0080); + /* enable auto negotiate, setup, disable fd */ + val = lp->a.read_bcr(ioaddr, 32) & ~0x98; + val |= 0x20; + lp->a.write_bcr(ioaddr, 32, val); + } + } + } else { + int first_phy = -1; + u16 bmcr; + u32 bcr9; + struct ethtool_cmd ecmd; + + /* + * There is really no good other way to handle multiple PHYs + * other than turning off all automatics + */ + val = lp->a.read_bcr(ioaddr, 2); + lp->a.write_bcr(ioaddr, 2, val & ~2); + val = lp->a.read_bcr(ioaddr, 32); + lp->a.write_bcr(ioaddr, 32, val & ~(1 << 7)); /* stop MII manager */ + + if (!(lp->options & PCNET32_PORT_ASEL)) { + /* setup ecmd */ + ecmd.port = PORT_MII; + ecmd.transceiver = XCVR_INTERNAL; + ecmd.autoneg = AUTONEG_DISABLE; + ecmd.speed = + lp-> + options & PCNET32_PORT_100 ? SPEED_100 : SPEED_10; + bcr9 = lp->a.read_bcr(ioaddr, 9); + + if (lp->options & PCNET32_PORT_FD) { + ecmd.duplex = DUPLEX_FULL; + bcr9 |= (1 << 0); + } else { + ecmd.duplex = DUPLEX_HALF; + bcr9 |= ~(1 << 0); + } + lp->a.write_bcr(ioaddr, 9, bcr9); } - mii_ethtool_sset(&lp->mii_if, &ecmd); - } - } - lp->mii_if.phy_id = first_phy; - if (netif_msg_link(lp)) - printk(KERN_INFO "%s: Using PHY number %d.\n", dev->name, first_phy); - } + + for (i = 0; i < PCNET32_MAX_PHYS; i++) { + if (lp->phymask & (1 << i)) { + /* isolate all but the first PHY */ + bmcr = mdio_read(dev, i, MII_BMCR); + if (first_phy == -1) { + first_phy = i; + mdio_write(dev, i, MII_BMCR, + bmcr & ~BMCR_ISOLATE); + } else { + mdio_write(dev, i, MII_BMCR, + bmcr | BMCR_ISOLATE); + } + /* use mii_ethtool_sset to setup PHY */ + lp->mii_if.phy_id = i; + ecmd.phy_address = i; + if (lp->options & PCNET32_PORT_ASEL) { + mii_ethtool_gset(&lp->mii_if, &ecmd); + ecmd.autoneg = AUTONEG_ENABLE; + } + mii_ethtool_sset(&lp->mii_if, &ecmd); + } + } + lp->mii_if.phy_id = first_phy; + if (netif_msg_link(lp)) + printk(KERN_INFO "%s: Using PHY number %d.\n", + dev->name, first_phy); + } #ifdef DO_DXSUFLO - if (lp->dxsuflo) { /* Disable transmit stop on underflow */ - val = lp->a.read_csr (ioaddr, 3); - val |= 0x40; - lp->a.write_csr (ioaddr, 3, val); - } + if (lp->dxsuflo) { /* Disable transmit stop on underflow */ + val = lp->a.read_csr(ioaddr, 3); + val |= 0x40; + lp->a.write_csr(ioaddr, 3, val); + } #endif - lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); - pcnet32_load_multicast(dev); - - if (pcnet32_init_ring(dev)) { - rc = -ENOMEM; - goto err_free_ring; - } - - /* Re-initialize the PCNET32, and start it when done. */ - lp->a.write_csr (ioaddr, 1, (lp->dma_addr + - offsetof(struct pcnet32_private, init_block)) & 0xffff); - lp->a.write_csr (ioaddr, 2, (lp->dma_addr + - offsetof(struct pcnet32_private, init_block)) >> 16); - - lp->a.write_csr (ioaddr, 4, 0x0915); - lp->a.write_csr (ioaddr, 0, 0x0001); - - netif_start_queue(dev); - - /* Print the link status and start the watchdog */ - pcnet32_check_media (dev, 1); - mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); - - i = 0; - while (i++ < 100) - if (lp->a.read_csr (ioaddr, 0) & 0x0100) - break; - /* - * We used to clear the InitDone bit, 0x0100, here but Mark Stockton - * reports that doing so triggers a bug in the '974. - */ - lp->a.write_csr (ioaddr, 0, 0x0042); - - if (netif_msg_ifup(lp)) - printk(KERN_DEBUG "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n", - dev->name, i, (u32) (lp->dma_addr + - offsetof(struct pcnet32_private, init_block)), - lp->a.read_csr(ioaddr, 0)); - - spin_unlock_irqrestore(&lp->lock, flags); - - return 0; /* Always succeed */ - -err_free_ring: - /* free any allocated skbuffs */ - for (i = 0; i < lp->rx_ring_size; i++) { - lp->rx_ring[i].status = 0; - if (lp->rx_skbuff[i]) { - pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2, - PCI_DMA_FROMDEVICE); - dev_kfree_skb(lp->rx_skbuff[i]); - } - lp->rx_skbuff[i] = NULL; - lp->rx_dma_addr[i] = 0; - } - - pcnet32_free_ring(dev); - - /* - * Switch back to 16bit mode to avoid problems with dumb - * DOS packet driver after a warm reboot - */ - lp->a.write_bcr (ioaddr, 20, 4); - -err_free_irq: - spin_unlock_irqrestore(&lp->lock, flags); - free_irq(dev->irq, dev); - return rc; + lp->init_block.mode = + le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); + pcnet32_load_multicast(dev); + + if (pcnet32_init_ring(dev)) { + rc = -ENOMEM; + goto err_free_ring; + } + + /* Re-initialize the PCNET32, and start it when done. */ + lp->a.write_csr(ioaddr, 1, (lp->dma_addr + + offsetof(struct pcnet32_private, + init_block)) & 0xffff); + lp->a.write_csr(ioaddr, 2, + (lp->dma_addr + + offsetof(struct pcnet32_private, init_block)) >> 16); + + lp->a.write_csr(ioaddr, 4, 0x0915); + lp->a.write_csr(ioaddr, 0, 0x0001); + + netif_start_queue(dev); + + /* Print the link status and start the watchdog */ + pcnet32_check_media(dev, 1); + mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); + + i = 0; + while (i++ < 100) + if (lp->a.read_csr(ioaddr, 0) & 0x0100) + break; + /* + * We used to clear the InitDone bit, 0x0100, here but Mark Stockton + * reports that doing so triggers a bug in the '974. + */ + lp->a.write_csr(ioaddr, 0, 0x0042); + + if (netif_msg_ifup(lp)) + printk(KERN_DEBUG + "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n", + dev->name, i, + (u32) (lp->dma_addr + + offsetof(struct pcnet32_private, init_block)), + lp->a.read_csr(ioaddr, 0)); + + spin_unlock_irqrestore(&lp->lock, flags); + + return 0; /* Always succeed */ + + err_free_ring: + /* free any allocated skbuffs */ + for (i = 0; i < lp->rx_ring_size; i++) { + lp->rx_ring[i].status = 0; + if (lp->rx_skbuff[i]) { + pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], + PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); + dev_kfree_skb(lp->rx_skbuff[i]); + } + lp->rx_skbuff[i] = NULL; + lp->rx_dma_addr[i] = 0; + } + + pcnet32_free_ring(dev); + + /* + * Switch back to 16bit mode to avoid problems with dumb + * DOS packet driver after a warm reboot + */ + lp->a.write_bcr(ioaddr, 20, 4); + + err_free_irq: + spin_unlock_irqrestore(&lp->lock, flags); + free_irq(dev->irq, dev); + return rc; } /* @@ -1840,722 +1921,792 @@ err_free_irq: * restarting the chip, but I'm too lazy to do so right now. dplatt@3do.com */ -static void -pcnet32_purge_tx_ring(struct net_device *dev) +static void pcnet32_purge_tx_ring(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - int i; - - for (i = 0; i < lp->tx_ring_size; i++) { - lp->tx_ring[i].status = 0; /* CPU owns buffer */ - wmb(); /* Make sure adapter sees owner change */ - if (lp->tx_skbuff[i]) { - pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], - lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE); - dev_kfree_skb_any(lp->tx_skbuff[i]); - } - lp->tx_skbuff[i] = NULL; - lp->tx_dma_addr[i] = 0; - } -} + struct pcnet32_private *lp = dev->priv; + int i; + for (i = 0; i < lp->tx_ring_size; i++) { + lp->tx_ring[i].status = 0; /* CPU owns buffer */ + wmb(); /* Make sure adapter sees owner change */ + if (lp->tx_skbuff[i]) { + pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], + lp->tx_skbuff[i]->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_any(lp->tx_skbuff[i]); + } + lp->tx_skbuff[i] = NULL; + lp->tx_dma_addr[i] = 0; + } +} /* Initialize the PCNET32 Rx and Tx rings. */ -static int -pcnet32_init_ring(struct net_device *dev) +static int pcnet32_init_ring(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - int i; - - lp->tx_full = 0; - lp->cur_rx = lp->cur_tx = 0; - lp->dirty_rx = lp->dirty_tx = 0; - - for (i = 0; i < lp->rx_ring_size; i++) { - struct sk_buff *rx_skbuff = lp->rx_skbuff[i]; - if (rx_skbuff == NULL) { - if (!(rx_skbuff = lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) { - /* there is not much, we can do at this point */ - if (pcnet32_debug & NETIF_MSG_DRV) - printk(KERN_ERR "%s: pcnet32_init_ring dev_alloc_skb failed.\n", - dev->name); - return -1; - } - skb_reserve (rx_skbuff, 2); - } - - rmb(); - if (lp->rx_dma_addr[i] == 0) - lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->data, - PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); - lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]); - lp->rx_ring[i].buf_length = le16_to_cpu(2-PKT_BUF_SZ); - wmb(); /* Make sure owner changes after all others are visible */ - lp->rx_ring[i].status = le16_to_cpu(0x8000); - } - /* The Tx buffer address is filled in as needed, but we do need to clear - * the upper ownership bit. */ - for (i = 0; i < lp->tx_ring_size; i++) { - lp->tx_ring[i].status = 0; /* CPU owns buffer */ - wmb(); /* Make sure adapter sees owner change */ - lp->tx_ring[i].base = 0; - lp->tx_dma_addr[i] = 0; - } - - lp->init_block.tlen_rlen = le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); - for (i = 0; i < 6; i++) - lp->init_block.phys_addr[i] = dev->dev_addr[i]; - lp->init_block.rx_ring = (u32)le32_to_cpu(lp->rx_ring_dma_addr); - lp->init_block.tx_ring = (u32)le32_to_cpu(lp->tx_ring_dma_addr); - wmb(); /* Make sure all changes are visible */ - return 0; + struct pcnet32_private *lp = dev->priv; + int i; + + lp->tx_full = 0; + lp->cur_rx = lp->cur_tx = 0; + lp->dirty_rx = lp->dirty_tx = 0; + + for (i = 0; i < lp->rx_ring_size; i++) { + struct sk_buff *rx_skbuff = lp->rx_skbuff[i]; + if (rx_skbuff == NULL) { + if (! + (rx_skbuff = lp->rx_skbuff[i] = + dev_alloc_skb(PKT_BUF_SZ))) { + /* there is not much, we can do at this point */ + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR + "%s: pcnet32_init_ring dev_alloc_skb failed.\n", + dev->name); + return -1; + } + skb_reserve(rx_skbuff, 2); + } + + rmb(); + if (lp->rx_dma_addr[i] == 0) + lp->rx_dma_addr[i] = + pci_map_single(lp->pci_dev, rx_skbuff->data, + PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); + lp->rx_ring[i].base = (u32) le32_to_cpu(lp->rx_dma_addr[i]); + lp->rx_ring[i].buf_length = le16_to_cpu(2 - PKT_BUF_SZ); + wmb(); /* Make sure owner changes after all others are visible */ + lp->rx_ring[i].status = le16_to_cpu(0x8000); + } + /* The Tx buffer address is filled in as needed, but we do need to clear + * the upper ownership bit. */ + for (i = 0; i < lp->tx_ring_size; i++) { + lp->tx_ring[i].status = 0; /* CPU owns buffer */ + wmb(); /* Make sure adapter sees owner change */ + lp->tx_ring[i].base = 0; + lp->tx_dma_addr[i] = 0; + } + + lp->init_block.tlen_rlen = + le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); + for (i = 0; i < 6; i++) + lp->init_block.phys_addr[i] = dev->dev_addr[i]; + lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); + lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); + wmb(); /* Make sure all changes are visible */ + return 0; } /* the pcnet32 has been issued a stop or reset. Wait for the stop bit * then flush the pending transmit operations, re-initialize the ring, * and tell the chip to initialize. */ -static void -pcnet32_restart(struct net_device *dev, unsigned int csr0_bits) +static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits) { - struct pcnet32_private *lp = dev->priv; - unsigned long ioaddr = dev->base_addr; - int i; + struct pcnet32_private *lp = dev->priv; + unsigned long ioaddr = dev->base_addr; + int i; - /* wait for stop */ - for (i=0; i<100; i++) - if (lp->a.read_csr(ioaddr, 0) & 0x0004) - break; + /* wait for stop */ + for (i = 0; i < 100; i++) + if (lp->a.read_csr(ioaddr, 0) & 0x0004) + break; - if (i >= 100 && netif_msg_drv(lp)) - printk(KERN_ERR "%s: pcnet32_restart timed out waiting for stop.\n", - dev->name); + if (i >= 100 && netif_msg_drv(lp)) + printk(KERN_ERR + "%s: pcnet32_restart timed out waiting for stop.\n", + dev->name); - pcnet32_purge_tx_ring(dev); - if (pcnet32_init_ring(dev)) - return; + pcnet32_purge_tx_ring(dev); + if (pcnet32_init_ring(dev)) + return; - /* ReInit Ring */ - lp->a.write_csr (ioaddr, 0, 1); - i = 0; - while (i++ < 1000) - if (lp->a.read_csr (ioaddr, 0) & 0x0100) - break; + /* ReInit Ring */ + lp->a.write_csr(ioaddr, 0, 1); + i = 0; + while (i++ < 1000) + if (lp->a.read_csr(ioaddr, 0) & 0x0100) + break; - lp->a.write_csr (ioaddr, 0, csr0_bits); + lp->a.write_csr(ioaddr, 0, csr0_bits); } - -static void -pcnet32_tx_timeout (struct net_device *dev) +static void pcnet32_tx_timeout(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - unsigned long ioaddr = dev->base_addr, flags; - - spin_lock_irqsave(&lp->lock, flags); - /* Transmitter timeout, serious problems. */ - if (pcnet32_debug & NETIF_MSG_DRV) - printk(KERN_ERR "%s: transmit timed out, status %4.4x, resetting.\n", - dev->name, lp->a.read_csr(ioaddr, 0)); - lp->a.write_csr (ioaddr, 0, 0x0004); - lp->stats.tx_errors++; - if (netif_msg_tx_err(lp)) { - int i; - printk(KERN_DEBUG " Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", - lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "", - lp->cur_rx); - for (i = 0 ; i < lp->rx_ring_size; i++) - printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", - le32_to_cpu(lp->rx_ring[i].base), - (-le16_to_cpu(lp->rx_ring[i].buf_length)) & 0xffff, - le32_to_cpu(lp->rx_ring[i].msg_length), - le16_to_cpu(lp->rx_ring[i].status)); - for (i = 0 ; i < lp->tx_ring_size; i++) - printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", - le32_to_cpu(lp->tx_ring[i].base), - (-le16_to_cpu(lp->tx_ring[i].length)) & 0xffff, - le32_to_cpu(lp->tx_ring[i].misc), - le16_to_cpu(lp->tx_ring[i].status)); - printk("\n"); - } - pcnet32_restart(dev, 0x0042); - - dev->trans_start = jiffies; - netif_wake_queue(dev); - - spin_unlock_irqrestore(&lp->lock, flags); -} + struct pcnet32_private *lp = dev->priv; + unsigned long ioaddr = dev->base_addr, flags; + + spin_lock_irqsave(&lp->lock, flags); + /* Transmitter timeout, serious problems. */ + if (pcnet32_debug & NETIF_MSG_DRV) + printk(KERN_ERR + "%s: transmit timed out, status %4.4x, resetting.\n", + dev->name, lp->a.read_csr(ioaddr, 0)); + lp->a.write_csr(ioaddr, 0, 0x0004); + lp->stats.tx_errors++; + if (netif_msg_tx_err(lp)) { + int i; + printk(KERN_DEBUG + " Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", + lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "", + lp->cur_rx); + for (i = 0; i < lp->rx_ring_size; i++) + printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", + le32_to_cpu(lp->rx_ring[i].base), + (-le16_to_cpu(lp->rx_ring[i].buf_length)) & + 0xffff, le32_to_cpu(lp->rx_ring[i].msg_length), + le16_to_cpu(lp->rx_ring[i].status)); + for (i = 0; i < lp->tx_ring_size; i++) + printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", + le32_to_cpu(lp->tx_ring[i].base), + (-le16_to_cpu(lp->tx_ring[i].length)) & 0xffff, + le32_to_cpu(lp->tx_ring[i].misc), + le16_to_cpu(lp->tx_ring[i].status)); + printk("\n"); + } + pcnet32_restart(dev, 0x0042); + dev->trans_start = jiffies; + netif_wake_queue(dev); -static int -pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) + spin_unlock_irqrestore(&lp->lock, flags); +} + +static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - unsigned long ioaddr = dev->base_addr; - u16 status; - int entry; - unsigned long flags; + struct pcnet32_private *lp = dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 status; + int entry; + unsigned long flags; - spin_lock_irqsave(&lp->lock, flags); + spin_lock_irqsave(&lp->lock, flags); - if (netif_msg_tx_queued(lp)) { - printk(KERN_DEBUG "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", - dev->name, lp->a.read_csr(ioaddr, 0)); - } + if (netif_msg_tx_queued(lp)) { + printk(KERN_DEBUG + "%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", + dev->name, lp->a.read_csr(ioaddr, 0)); + } - /* Default status -- will not enable Successful-TxDone - * interrupt when that option is available to us. - */ - status = 0x8300; + /* Default status -- will not enable Successful-TxDone + * interrupt when that option is available to us. + */ + status = 0x8300; - /* Fill in a Tx ring entry */ + /* Fill in a Tx ring entry */ - /* Mask to ring buffer boundary. */ - entry = lp->cur_tx & lp->tx_mod_mask; + /* Mask to ring buffer boundary. */ + entry = lp->cur_tx & lp->tx_mod_mask; - /* Caution: the write order is important here, set the status - * with the "ownership" bits last. */ + /* Caution: the write order is important here, set the status + * with the "ownership" bits last. */ - lp->tx_ring[entry].length = le16_to_cpu(-skb->len); + lp->tx_ring[entry].length = le16_to_cpu(-skb->len); - lp->tx_ring[entry].misc = 0x00000000; + lp->tx_ring[entry].misc = 0x00000000; - lp->tx_skbuff[entry] = skb; - lp->tx_dma_addr[entry] = pci_map_single(lp->pci_dev, skb->data, skb->len, - PCI_DMA_TODEVICE); - lp->tx_ring[entry].base = (u32)le32_to_cpu(lp->tx_dma_addr[entry]); - wmb(); /* Make sure owner changes after all others are visible */ - lp->tx_ring[entry].status = le16_to_cpu(status); + lp->tx_skbuff[entry] = skb; + lp->tx_dma_addr[entry] = + pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); + lp->tx_ring[entry].base = (u32) le32_to_cpu(lp->tx_dma_addr[entry]); + wmb(); /* Make sure owner changes after all others are visible */ + lp->tx_ring[entry].status = le16_to_cpu(status); - lp->cur_tx++; - lp->stats.tx_bytes += skb->len; + lp->cur_tx++; + lp->stats.tx_bytes += skb->len; - /* Trigger an immediate send poll. */ - lp->a.write_csr (ioaddr, 0, 0x0048); + /* Trigger an immediate send poll. */ + lp->a.write_csr(ioaddr, 0, 0x0048); - dev->trans_start = jiffies; + dev->trans_start = jiffies; - if (lp->tx_ring[(entry+1) & lp->tx_mod_mask].base != 0) { - lp->tx_full = 1; - netif_stop_queue(dev); - } - spin_unlock_irqrestore(&lp->lock, flags); - return 0; + if (lp->tx_ring[(entry + 1) & lp->tx_mod_mask].base != 0) { + lp->tx_full = 1; + netif_stop_queue(dev); + } + spin_unlock_irqrestore(&lp->lock, flags); + return 0; } /* The PCNET32 interrupt handler. */ static irqreturn_t -pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) +pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct net_device *dev = dev_id; - struct pcnet32_private *lp; - unsigned long ioaddr; - u16 csr0,rap; - int boguscnt = max_interrupt_work; - int must_restart; - - if (!dev) { - if (pcnet32_debug & NETIF_MSG_INTR) - printk (KERN_DEBUG "%s(): irq %d for unknown device\n", - __FUNCTION__, irq); - return IRQ_NONE; - } - - ioaddr = dev->base_addr; - lp = dev->priv; - - spin_lock(&lp->lock); - - rap = lp->a.read_rap(ioaddr); - while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8f00 && --boguscnt >= 0) { - if (csr0 == 0xffff) { - break; /* PCMCIA remove happened */ + struct net_device *dev = dev_id; + struct pcnet32_private *lp; + unsigned long ioaddr; + u16 csr0, rap; + int boguscnt = max_interrupt_work; + int must_restart; + + if (!dev) { + if (pcnet32_debug & NETIF_MSG_INTR) + printk(KERN_DEBUG "%s(): irq %d for unknown device\n", + __FUNCTION__, irq); + return IRQ_NONE; } - /* Acknowledge all of the current interrupt sources ASAP. */ - lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f); - must_restart = 0; + ioaddr = dev->base_addr; + lp = dev->priv; - if (netif_msg_intr(lp)) - printk(KERN_DEBUG "%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", - dev->name, csr0, lp->a.read_csr (ioaddr, 0)); - - if (csr0 & 0x0400) /* Rx interrupt */ - pcnet32_rx(dev); - - if (csr0 & 0x0200) { /* Tx-done interrupt */ - unsigned int dirty_tx = lp->dirty_tx; - int delta; - - while (dirty_tx != lp->cur_tx) { - int entry = dirty_tx & lp->tx_mod_mask; - int status = (short)le16_to_cpu(lp->tx_ring[entry].status); - - if (status < 0) - break; /* It still hasn't been Txed */ - - lp->tx_ring[entry].base = 0; - - if (status & 0x4000) { - /* There was an major error, log it. */ - int err_status = le32_to_cpu(lp->tx_ring[entry].misc); - lp->stats.tx_errors++; - if (netif_msg_tx_err(lp)) - printk(KERN_ERR "%s: Tx error status=%04x err_status=%08x\n", - dev->name, status, err_status); - if (err_status & 0x04000000) lp->stats.tx_aborted_errors++; - if (err_status & 0x08000000) lp->stats.tx_carrier_errors++; - if (err_status & 0x10000000) lp->stats.tx_window_errors++; + spin_lock(&lp->lock); + + rap = lp->a.read_rap(ioaddr); + while ((csr0 = lp->a.read_csr(ioaddr, 0)) & 0x8f00 && --boguscnt >= 0) { + if (csr0 == 0xffff) { + break; /* PCMCIA remove happened */ + } + /* Acknowledge all of the current interrupt sources ASAP. */ + lp->a.write_csr(ioaddr, 0, csr0 & ~0x004f); + + must_restart = 0; + + if (netif_msg_intr(lp)) + printk(KERN_DEBUG + "%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", + dev->name, csr0, lp->a.read_csr(ioaddr, 0)); + + if (csr0 & 0x0400) /* Rx interrupt */ + pcnet32_rx(dev); + + if (csr0 & 0x0200) { /* Tx-done interrupt */ + unsigned int dirty_tx = lp->dirty_tx; + int delta; + + while (dirty_tx != lp->cur_tx) { + int entry = dirty_tx & lp->tx_mod_mask; + int status = + (short)le16_to_cpu(lp->tx_ring[entry]. + status); + + if (status < 0) + break; /* It still hasn't been Txed */ + + lp->tx_ring[entry].base = 0; + + if (status & 0x4000) { + /* There was an major error, log it. */ + int err_status = + le32_to_cpu(lp->tx_ring[entry]. + misc); + lp->stats.tx_errors++; + if (netif_msg_tx_err(lp)) + printk(KERN_ERR + "%s: Tx error status=%04x err_status=%08x\n", + dev->name, status, + err_status); + if (err_status & 0x04000000) + lp->stats.tx_aborted_errors++; + if (err_status & 0x08000000) + lp->stats.tx_carrier_errors++; + if (err_status & 0x10000000) + lp->stats.tx_window_errors++; #ifndef DO_DXSUFLO - if (err_status & 0x40000000) { - lp->stats.tx_fifo_errors++; - /* Ackk! On FIFO errors the Tx unit is turned off! */ - /* Remove this verbosity later! */ - if (netif_msg_tx_err(lp)) - printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n", - dev->name, csr0); - must_restart = 1; - } + if (err_status & 0x40000000) { + lp->stats.tx_fifo_errors++; + /* Ackk! On FIFO errors the Tx unit is turned off! */ + /* Remove this verbosity later! */ + if (netif_msg_tx_err(lp)) + printk(KERN_ERR + "%s: Tx FIFO error! CSR0=%4.4x\n", + dev->name, csr0); + must_restart = 1; + } #else - if (err_status & 0x40000000) { - lp->stats.tx_fifo_errors++; - if (! lp->dxsuflo) { /* If controller doesn't recover ... */ - /* Ackk! On FIFO errors the Tx unit is turned off! */ - /* Remove this verbosity later! */ - if (netif_msg_tx_err(lp)) - printk(KERN_ERR "%s: Tx FIFO error! CSR0=%4.4x\n", - dev->name, csr0); - must_restart = 1; - } - } + if (err_status & 0x40000000) { + lp->stats.tx_fifo_errors++; + if (!lp->dxsuflo) { /* If controller doesn't recover ... */ + /* Ackk! On FIFO errors the Tx unit is turned off! */ + /* Remove this verbosity later! */ + if (netif_msg_tx_err + (lp)) + printk(KERN_ERR + "%s: Tx FIFO error! CSR0=%4.4x\n", + dev-> + name, + csr0); + must_restart = 1; + } + } #endif - } else { - if (status & 0x1800) - lp->stats.collisions++; - lp->stats.tx_packets++; + } else { + if (status & 0x1800) + lp->stats.collisions++; + lp->stats.tx_packets++; + } + + /* We must free the original skb */ + if (lp->tx_skbuff[entry]) { + pci_unmap_single(lp->pci_dev, + lp->tx_dma_addr[entry], + lp->tx_skbuff[entry]-> + len, PCI_DMA_TODEVICE); + dev_kfree_skb_irq(lp->tx_skbuff[entry]); + lp->tx_skbuff[entry] = NULL; + lp->tx_dma_addr[entry] = 0; + } + dirty_tx++; + } + + delta = + (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask + + lp->tx_ring_size); + if (delta > lp->tx_ring_size) { + if (netif_msg_drv(lp)) + printk(KERN_ERR + "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dev->name, dirty_tx, lp->cur_tx, + lp->tx_full); + dirty_tx += lp->tx_ring_size; + delta -= lp->tx_ring_size; + } + + if (lp->tx_full && + netif_queue_stopped(dev) && + delta < lp->tx_ring_size - 2) { + /* The ring is no longer full, clear tbusy. */ + lp->tx_full = 0; + netif_wake_queue(dev); + } + lp->dirty_tx = dirty_tx; + } + + /* Log misc errors. */ + if (csr0 & 0x4000) + lp->stats.tx_errors++; /* Tx babble. */ + if (csr0 & 0x1000) { + /* + * this happens when our receive ring is full. This shouldn't + * be a problem as we will see normal rx interrupts for the frames + * in the receive ring. But there are some PCI chipsets (I can + * reproduce this on SP3G with Intel saturn chipset) which have + * sometimes problems and will fill up the receive ring with + * error descriptors. In this situation we don't get a rx + * interrupt, but a missed frame interrupt sooner or later. + * So we try to clean up our receive ring here. + */ + pcnet32_rx(dev); + lp->stats.rx_errors++; /* Missed a Rx frame. */ + } + if (csr0 & 0x0800) { + if (netif_msg_drv(lp)) + printk(KERN_ERR + "%s: Bus master arbitration failure, status %4.4x.\n", + dev->name, csr0); + /* unlike for the lance, there is no restart needed */ } - /* We must free the original skb */ - if (lp->tx_skbuff[entry]) { - pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[entry], - lp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(lp->tx_skbuff[entry]); - lp->tx_skbuff[entry] = NULL; - lp->tx_dma_addr[entry] = 0; + if (must_restart) { + /* reset the chip to clear the error condition, then restart */ + lp->a.reset(ioaddr); + lp->a.write_csr(ioaddr, 4, 0x0915); + pcnet32_restart(dev, 0x0002); + netif_wake_queue(dev); } - dirty_tx++; - } - - delta = (lp->cur_tx - dirty_tx) & (lp->tx_mod_mask + lp->tx_ring_size); - if (delta > lp->tx_ring_size) { - if (netif_msg_drv(lp)) - printk(KERN_ERR "%s: out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dev->name, dirty_tx, lp->cur_tx, lp->tx_full); - dirty_tx += lp->tx_ring_size; - delta -= lp->tx_ring_size; - } - - if (lp->tx_full && - netif_queue_stopped(dev) && - delta < lp->tx_ring_size - 2) { - /* The ring is no longer full, clear tbusy. */ - lp->tx_full = 0; - netif_wake_queue (dev); - } - lp->dirty_tx = dirty_tx; - } - - /* Log misc errors. */ - if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */ - if (csr0 & 0x1000) { - /* - * this happens when our receive ring is full. This shouldn't - * be a problem as we will see normal rx interrupts for the frames - * in the receive ring. But there are some PCI chipsets (I can - * reproduce this on SP3G with Intel saturn chipset) which have - * sometimes problems and will fill up the receive ring with - * error descriptors. In this situation we don't get a rx - * interrupt, but a missed frame interrupt sooner or later. - * So we try to clean up our receive ring here. - */ - pcnet32_rx(dev); - lp->stats.rx_errors++; /* Missed a Rx frame. */ - } - if (csr0 & 0x0800) { - if (netif_msg_drv(lp)) - printk(KERN_ERR "%s: Bus master arbitration failure, status %4.4x.\n", - dev->name, csr0); - /* unlike for the lance, there is no restart needed */ - } - - if (must_restart) { - /* reset the chip to clear the error condition, then restart */ - lp->a.reset(ioaddr); - lp->a.write_csr(ioaddr, 4, 0x0915); - pcnet32_restart(dev, 0x0002); - netif_wake_queue(dev); - } - } - - /* Set interrupt enable. */ - lp->a.write_csr (ioaddr, 0, 0x0040); - lp->a.write_rap (ioaddr,rap); - - if (netif_msg_intr(lp)) - printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n", - dev->name, lp->a.read_csr (ioaddr, 0)); - - spin_unlock(&lp->lock); - - return IRQ_HANDLED; + } + + /* Set interrupt enable. */ + lp->a.write_csr(ioaddr, 0, 0x0040); + lp->a.write_rap(ioaddr, rap); + + if (netif_msg_intr(lp)) + printk(KERN_DEBUG "%s: exiting interrupt, csr0=%#4.4x.\n", + dev->name, lp->a.read_csr(ioaddr, 0)); + + spin_unlock(&lp->lock); + + return IRQ_HANDLED; } -static int -pcnet32_rx(struct net_device *dev) +static int pcnet32_rx(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - int entry = lp->cur_rx & lp->rx_mod_mask; - int boguscnt = lp->rx_ring_size / 2; - - /* If we own the next entry, it's a new packet. Send it up. */ - while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) { - int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8; - - if (status != 0x03) { /* There was an error. */ - /* - * There is a tricky error noted by John Murphy, - * to Russ Nelson: Even with full-sized - * buffers it's possible for a jabber packet to use two - * buffers, with only the last correctly noting the error. - */ - if (status & 0x01) /* Only count a general error at the */ - lp->stats.rx_errors++; /* end of a packet.*/ - if (status & 0x20) lp->stats.rx_frame_errors++; - if (status & 0x10) lp->stats.rx_over_errors++; - if (status & 0x08) lp->stats.rx_crc_errors++; - if (status & 0x04) lp->stats.rx_fifo_errors++; - lp->rx_ring[entry].status &= le16_to_cpu(0x03ff); - } else { - /* Malloc up new buffer, compatible with net-2e. */ - short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4; - struct sk_buff *skb; - - /* Discard oversize frames. */ - if (unlikely(pkt_len > PKT_BUF_SZ - 2)) { - if (netif_msg_drv(lp)) - printk(KERN_ERR "%s: Impossible packet size %d!\n", - dev->name, pkt_len); - lp->stats.rx_errors++; - } else if (pkt_len < 60) { - if (netif_msg_rx_err(lp)) - printk(KERN_ERR "%s: Runt packet!\n", dev->name); - lp->stats.rx_errors++; - } else { - int rx_in_place = 0; - - if (pkt_len > rx_copybreak) { - struct sk_buff *newskb; - - if ((newskb = dev_alloc_skb(PKT_BUF_SZ))) { - skb_reserve (newskb, 2); - skb = lp->rx_skbuff[entry]; - pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[entry], - PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); - skb_put (skb, pkt_len); - lp->rx_skbuff[entry] = newskb; - newskb->dev = dev; - lp->rx_dma_addr[entry] = - pci_map_single(lp->pci_dev, newskb->data, - PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE); - lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]); - rx_in_place = 1; - } else - skb = NULL; + struct pcnet32_private *lp = dev->priv; + int entry = lp->cur_rx & lp->rx_mod_mask; + int boguscnt = lp->rx_ring_size / 2; + + /* If we own the next entry, it's a new packet. Send it up. */ + while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) { + int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8; + + if (status != 0x03) { /* There was an error. */ + /* + * There is a tricky error noted by John Murphy, + * to Russ Nelson: Even with full-sized + * buffers it's possible for a jabber packet to use two + * buffers, with only the last correctly noting the error. + */ + if (status & 0x01) /* Only count a general error at the */ + lp->stats.rx_errors++; /* end of a packet. */ + if (status & 0x20) + lp->stats.rx_frame_errors++; + if (status & 0x10) + lp->stats.rx_over_errors++; + if (status & 0x08) + lp->stats.rx_crc_errors++; + if (status & 0x04) + lp->stats.rx_fifo_errors++; + lp->rx_ring[entry].status &= le16_to_cpu(0x03ff); } else { - skb = dev_alloc_skb(pkt_len+2); - } - - if (skb == NULL) { - int i; - if (netif_msg_drv(lp)) - printk(KERN_ERR "%s: Memory squeeze, deferring packet.\n", - dev->name); - for (i = 0; i < lp->rx_ring_size; i++) - if ((short)le16_to_cpu(lp->rx_ring[(entry+i) - & lp->rx_mod_mask].status) < 0) - break; - - if (i > lp->rx_ring_size -2) { - lp->stats.rx_dropped++; - lp->rx_ring[entry].status |= le16_to_cpu(0x8000); - wmb(); /* Make sure adapter sees owner change */ - lp->cur_rx++; - } - break; - } - skb->dev = dev; - if (!rx_in_place) { - skb_reserve(skb,2); /* 16 byte align */ - skb_put(skb,pkt_len); /* Make room */ - pci_dma_sync_single_for_cpu(lp->pci_dev, - lp->rx_dma_addr[entry], - PKT_BUF_SZ-2, - PCI_DMA_FROMDEVICE); - eth_copy_and_sum(skb, - (unsigned char *)(lp->rx_skbuff[entry]->data), - pkt_len,0); - pci_dma_sync_single_for_device(lp->pci_dev, - lp->rx_dma_addr[entry], - PKT_BUF_SZ-2, - PCI_DMA_FROMDEVICE); + /* Malloc up new buffer, compatible with net-2e. */ + short pkt_len = + (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff) + - 4; + struct sk_buff *skb; + + /* Discard oversize frames. */ + if (unlikely(pkt_len > PKT_BUF_SZ - 2)) { + if (netif_msg_drv(lp)) + printk(KERN_ERR + "%s: Impossible packet size %d!\n", + dev->name, pkt_len); + lp->stats.rx_errors++; + } else if (pkt_len < 60) { + if (netif_msg_rx_err(lp)) + printk(KERN_ERR "%s: Runt packet!\n", + dev->name); + lp->stats.rx_errors++; + } else { + int rx_in_place = 0; + + if (pkt_len > rx_copybreak) { + struct sk_buff *newskb; + + if ((newskb = + dev_alloc_skb(PKT_BUF_SZ))) { + skb_reserve(newskb, 2); + skb = lp->rx_skbuff[entry]; + pci_unmap_single(lp->pci_dev, + lp-> + rx_dma_addr + [entry], + PKT_BUF_SZ - 2, + PCI_DMA_FROMDEVICE); + skb_put(skb, pkt_len); + lp->rx_skbuff[entry] = newskb; + newskb->dev = dev; + lp->rx_dma_addr[entry] = + pci_map_single(lp->pci_dev, + newskb->data, + PKT_BUF_SZ - + 2, + PCI_DMA_FROMDEVICE); + lp->rx_ring[entry].base = + le32_to_cpu(lp-> + rx_dma_addr + [entry]); + rx_in_place = 1; + } else + skb = NULL; + } else { + skb = dev_alloc_skb(pkt_len + 2); + } + + if (skb == NULL) { + int i; + if (netif_msg_drv(lp)) + printk(KERN_ERR + "%s: Memory squeeze, deferring packet.\n", + dev->name); + for (i = 0; i < lp->rx_ring_size; i++) + if ((short) + le16_to_cpu(lp-> + rx_ring[(entry + + i) + & lp-> + rx_mod_mask]. + status) < 0) + break; + + if (i > lp->rx_ring_size - 2) { + lp->stats.rx_dropped++; + lp->rx_ring[entry].status |= + le16_to_cpu(0x8000); + wmb(); /* Make sure adapter sees owner change */ + lp->cur_rx++; + } + break; + } + skb->dev = dev; + if (!rx_in_place) { + skb_reserve(skb, 2); /* 16 byte align */ + skb_put(skb, pkt_len); /* Make room */ + pci_dma_sync_single_for_cpu(lp->pci_dev, + lp-> + rx_dma_addr + [entry], + PKT_BUF_SZ - + 2, + PCI_DMA_FROMDEVICE); + eth_copy_and_sum(skb, + (unsigned char *)(lp-> + rx_skbuff + [entry]-> + data), + pkt_len, 0); + pci_dma_sync_single_for_device(lp-> + pci_dev, + lp-> + rx_dma_addr + [entry], + PKT_BUF_SZ + - 2, + PCI_DMA_FROMDEVICE); + } + lp->stats.rx_bytes += skb->len; + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->last_rx = jiffies; + lp->stats.rx_packets++; + } } - lp->stats.rx_bytes += skb->len; - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - dev->last_rx = jiffies; - lp->stats.rx_packets++; - } + /* + * The docs say that the buffer length isn't touched, but Andrew Boyd + * of QNX reports that some revs of the 79C965 clear it. + */ + lp->rx_ring[entry].buf_length = le16_to_cpu(2 - PKT_BUF_SZ); + wmb(); /* Make sure owner changes after all others are visible */ + lp->rx_ring[entry].status |= le16_to_cpu(0x8000); + entry = (++lp->cur_rx) & lp->rx_mod_mask; + if (--boguscnt <= 0) + break; /* don't stay in loop forever */ } - /* - * The docs say that the buffer length isn't touched, but Andrew Boyd - * of QNX reports that some revs of the 79C965 clear it. - */ - lp->rx_ring[entry].buf_length = le16_to_cpu(2-PKT_BUF_SZ); - wmb(); /* Make sure owner changes after all others are visible */ - lp->rx_ring[entry].status |= le16_to_cpu(0x8000); - entry = (++lp->cur_rx) & lp->rx_mod_mask; - if (--boguscnt <= 0) break; /* don't stay in loop forever */ - } - - return 0; + + return 0; } -static int -pcnet32_close(struct net_device *dev) +static int pcnet32_close(struct net_device *dev) { - unsigned long ioaddr = dev->base_addr; - struct pcnet32_private *lp = dev->priv; - int i; - unsigned long flags; + unsigned long ioaddr = dev->base_addr; + struct pcnet32_private *lp = dev->priv; + int i; + unsigned long flags; - del_timer_sync(&lp->watchdog_timer); + del_timer_sync(&lp->watchdog_timer); - netif_stop_queue(dev); + netif_stop_queue(dev); - spin_lock_irqsave(&lp->lock, flags); + spin_lock_irqsave(&lp->lock, flags); - lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112); + lp->stats.rx_missed_errors = lp->a.read_csr(ioaddr, 112); - if (netif_msg_ifdown(lp)) - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, lp->a.read_csr (ioaddr, 0)); + if (netif_msg_ifdown(lp)) + printk(KERN_DEBUG + "%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, lp->a.read_csr(ioaddr, 0)); - /* We stop the PCNET32 here -- it occasionally polls memory if we don't. */ - lp->a.write_csr (ioaddr, 0, 0x0004); + /* We stop the PCNET32 here -- it occasionally polls memory if we don't. */ + lp->a.write_csr(ioaddr, 0, 0x0004); - /* - * Switch back to 16bit mode to avoid problems with dumb - * DOS packet driver after a warm reboot - */ - lp->a.write_bcr (ioaddr, 20, 4); + /* + * Switch back to 16bit mode to avoid problems with dumb + * DOS packet driver after a warm reboot + */ + lp->a.write_bcr(ioaddr, 20, 4); - spin_unlock_irqrestore(&lp->lock, flags); + spin_unlock_irqrestore(&lp->lock, flags); - free_irq(dev->irq, dev); + free_irq(dev->irq, dev); - spin_lock_irqsave(&lp->lock, flags); + spin_lock_irqsave(&lp->lock, flags); - /* free all allocated skbuffs */ - for (i = 0; i < lp->rx_ring_size; i++) { - lp->rx_ring[i].status = 0; - wmb(); /* Make sure adapter sees owner change */ - if (lp->rx_skbuff[i]) { - pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], PKT_BUF_SZ-2, - PCI_DMA_FROMDEVICE); - dev_kfree_skb(lp->rx_skbuff[i]); + /* free all allocated skbuffs */ + for (i = 0; i < lp->rx_ring_size; i++) { + lp->rx_ring[i].status = 0; + wmb(); /* Make sure adapter sees owner change */ + if (lp->rx_skbuff[i]) { + pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], + PKT_BUF_SZ - 2, PCI_DMA_FROMDEVICE); + dev_kfree_skb(lp->rx_skbuff[i]); + } + lp->rx_skbuff[i] = NULL; + lp->rx_dma_addr[i] = 0; } - lp->rx_skbuff[i] = NULL; - lp->rx_dma_addr[i] = 0; - } - for (i = 0; i < lp->tx_ring_size; i++) { - lp->tx_ring[i].status = 0; /* CPU owns buffer */ - wmb(); /* Make sure adapter sees owner change */ - if (lp->tx_skbuff[i]) { - pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], - lp->tx_skbuff[i]->len, PCI_DMA_TODEVICE); - dev_kfree_skb(lp->tx_skbuff[i]); + for (i = 0; i < lp->tx_ring_size; i++) { + lp->tx_ring[i].status = 0; /* CPU owns buffer */ + wmb(); /* Make sure adapter sees owner change */ + if (lp->tx_skbuff[i]) { + pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], + lp->tx_skbuff[i]->len, + PCI_DMA_TODEVICE); + dev_kfree_skb(lp->tx_skbuff[i]); + } + lp->tx_skbuff[i] = NULL; + lp->tx_dma_addr[i] = 0; } - lp->tx_skbuff[i] = NULL; - lp->tx_dma_addr[i] = 0; - } - spin_unlock_irqrestore(&lp->lock, flags); + spin_unlock_irqrestore(&lp->lock, flags); - return 0; + return 0; } -static struct net_device_stats * -pcnet32_get_stats(struct net_device *dev) +static struct net_device_stats *pcnet32_get_stats(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - unsigned long ioaddr = dev->base_addr; - u16 saved_addr; - unsigned long flags; - - spin_lock_irqsave(&lp->lock, flags); - saved_addr = lp->a.read_rap(ioaddr); - lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112); - lp->a.write_rap(ioaddr, saved_addr); - spin_unlock_irqrestore(&lp->lock, flags); - - return &lp->stats; + struct pcnet32_private *lp = dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 saved_addr; + unsigned long flags; + + spin_lock_irqsave(&lp->lock, flags); + saved_addr = lp->a.read_rap(ioaddr); + lp->stats.rx_missed_errors = lp->a.read_csr(ioaddr, 112); + lp->a.write_rap(ioaddr, saved_addr); + spin_unlock_irqrestore(&lp->lock, flags); + + return &lp->stats; } /* taken from the sunlance driver, which it took from the depca driver */ -static void pcnet32_load_multicast (struct net_device *dev) +static void pcnet32_load_multicast(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - volatile struct pcnet32_init_block *ib = &lp->init_block; - volatile u16 *mcast_table = (u16 *)&ib->filter; - struct dev_mc_list *dmi=dev->mc_list; - char *addrs; - int i; - u32 crc; - - /* set all multicast bits */ - if (dev->flags & IFF_ALLMULTI) { - ib->filter[0] = 0xffffffff; - ib->filter[1] = 0xffffffff; + struct pcnet32_private *lp = dev->priv; + volatile struct pcnet32_init_block *ib = &lp->init_block; + volatile u16 *mcast_table = (u16 *) & ib->filter; + struct dev_mc_list *dmi = dev->mc_list; + char *addrs; + int i; + u32 crc; + + /* set all multicast bits */ + if (dev->flags & IFF_ALLMULTI) { + ib->filter[0] = 0xffffffff; + ib->filter[1] = 0xffffffff; + return; + } + /* clear the multicast filter */ + ib->filter[0] = 0; + ib->filter[1] = 0; + + /* Add addresses */ + for (i = 0; i < dev->mc_count; i++) { + addrs = dmi->dmi_addr; + dmi = dmi->next; + + /* multicast address? */ + if (!(*addrs & 1)) + continue; + + crc = ether_crc_le(6, addrs); + crc = crc >> 26; + mcast_table[crc >> 4] = + le16_to_cpu(le16_to_cpu(mcast_table[crc >> 4]) | + (1 << (crc & 0xf))); + } return; - } - /* clear the multicast filter */ - ib->filter[0] = 0; - ib->filter[1] = 0; - - /* Add addresses */ - for (i = 0; i < dev->mc_count; i++) { - addrs = dmi->dmi_addr; - dmi = dmi->next; - - /* multicast address? */ - if (!(*addrs & 1)) - continue; - - crc = ether_crc_le(6, addrs); - crc = crc >> 26; - mcast_table [crc >> 4] = le16_to_cpu( - le16_to_cpu(mcast_table [crc >> 4]) | (1 << (crc & 0xf))); - } - return; } - /* * Set or clear the multicast filter for this adaptor. */ static void pcnet32_set_multicast_list(struct net_device *dev) { - unsigned long ioaddr = dev->base_addr, flags; - struct pcnet32_private *lp = dev->priv; - - spin_lock_irqsave(&lp->lock, flags); - if (dev->flags&IFF_PROMISC) { - /* Log any net taps. */ - if (netif_msg_hw(lp)) - printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name); - lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << 7); - } else { - lp->init_block.mode = le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); - pcnet32_load_multicast (dev); - } - - lp->a.write_csr (ioaddr, 0, 0x0004); /* Temporarily stop the lance. */ - pcnet32_restart(dev, 0x0042); /* Resume normal operation */ - netif_wake_queue(dev); - - spin_unlock_irqrestore(&lp->lock, flags); + unsigned long ioaddr = dev->base_addr, flags; + struct pcnet32_private *lp = dev->priv; + + spin_lock_irqsave(&lp->lock, flags); + if (dev->flags & IFF_PROMISC) { + /* Log any net taps. */ + if (netif_msg_hw(lp)) + printk(KERN_INFO "%s: Promiscuous mode enabled.\n", + dev->name); + lp->init_block.mode = + le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << + 7); + } else { + lp->init_block.mode = + le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); + pcnet32_load_multicast(dev); + } + + lp->a.write_csr(ioaddr, 0, 0x0004); /* Temporarily stop the lance. */ + pcnet32_restart(dev, 0x0042); /* Resume normal operation */ + netif_wake_queue(dev); + + spin_unlock_irqrestore(&lp->lock, flags); } /* This routine assumes that the lp->lock is held */ static int mdio_read(struct net_device *dev, int phy_id, int reg_num) { - struct pcnet32_private *lp = dev->priv; - unsigned long ioaddr = dev->base_addr; - u16 val_out; + struct pcnet32_private *lp = dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 val_out; - if (!lp->mii) - return 0; + if (!lp->mii) + return 0; - lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f)); - val_out = lp->a.read_bcr(ioaddr, 34); + lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f)); + val_out = lp->a.read_bcr(ioaddr, 34); - return val_out; + return val_out; } /* This routine assumes that the lp->lock is held */ static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val) { - struct pcnet32_private *lp = dev->priv; - unsigned long ioaddr = dev->base_addr; + struct pcnet32_private *lp = dev->priv; + unsigned long ioaddr = dev->base_addr; - if (!lp->mii) - return; + if (!lp->mii) + return; - lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f)); - lp->a.write_bcr(ioaddr, 34, val); + lp->a.write_bcr(ioaddr, 33, ((phy_id & 0x1f) << 5) | (reg_num & 0x1f)); + lp->a.write_bcr(ioaddr, 34, val); } static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct pcnet32_private *lp = dev->priv; - int rc; - unsigned long flags; + struct pcnet32_private *lp = dev->priv; + int rc; + unsigned long flags; - /* SIOC[GS]MIIxxx ioctls */ - if (lp->mii) { - spin_lock_irqsave(&lp->lock, flags); - rc = generic_mii_ioctl(&lp->mii_if, if_mii(rq), cmd, NULL); - spin_unlock_irqrestore(&lp->lock, flags); - } else { - rc = -EOPNOTSUPP; - } + /* SIOC[GS]MIIxxx ioctls */ + if (lp->mii) { + spin_lock_irqsave(&lp->lock, flags); + rc = generic_mii_ioctl(&lp->mii_if, if_mii(rq), cmd, NULL); + spin_unlock_irqrestore(&lp->lock, flags); + } else { + rc = -EOPNOTSUPP; + } - return rc; + return rc; } static int pcnet32_check_otherphy(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - struct mii_if_info mii = lp->mii_if; - u16 bmcr; - int i; - - for (i = 0; i < PCNET32_MAX_PHYS; i++) { - if (i == lp->mii_if.phy_id) - continue; /* skip active phy */ - if (lp->phymask & (1 << i)) { - mii.phy_id = i; - if (mii_link_ok(&mii)) { - /* found PHY with active link */ - if (netif_msg_link(lp)) - printk(KERN_INFO "%s: Using PHY number %d.\n", dev->name, i); - - /* isolate inactive phy */ - bmcr = mdio_read(dev, lp->mii_if.phy_id, MII_BMCR); - mdio_write(dev, lp->mii_if.phy_id, MII_BMCR, bmcr | BMCR_ISOLATE); - - /* de-isolate new phy */ - bmcr = mdio_read(dev, i, MII_BMCR); - mdio_write(dev, i, MII_BMCR, bmcr & ~BMCR_ISOLATE); + struct pcnet32_private *lp = dev->priv; + struct mii_if_info mii = lp->mii_if; + u16 bmcr; + int i; - /* set new phy address */ - lp->mii_if.phy_id = i; - return 1; - } + for (i = 0; i < PCNET32_MAX_PHYS; i++) { + if (i == lp->mii_if.phy_id) + continue; /* skip active phy */ + if (lp->phymask & (1 << i)) { + mii.phy_id = i; + if (mii_link_ok(&mii)) { + /* found PHY with active link */ + if (netif_msg_link(lp)) + printk(KERN_INFO + "%s: Using PHY number %d.\n", + dev->name, i); + + /* isolate inactive phy */ + bmcr = + mdio_read(dev, lp->mii_if.phy_id, MII_BMCR); + mdio_write(dev, lp->mii_if.phy_id, MII_BMCR, + bmcr | BMCR_ISOLATE); + + /* de-isolate new phy */ + bmcr = mdio_read(dev, i, MII_BMCR); + mdio_write(dev, i, MII_BMCR, + bmcr & ~BMCR_ISOLATE); + + /* set new phy address */ + lp->mii_if.phy_id = i; + return 1; + } + } } - } - return 0; + return 0; } /* @@ -2568,51 +2719,53 @@ static int pcnet32_check_otherphy(struct net_device *dev) static void pcnet32_check_media(struct net_device *dev, int verbose) { - struct pcnet32_private *lp = dev->priv; - int curr_link; - int prev_link = netif_carrier_ok(dev) ? 1 : 0; - u32 bcr9; - - if (lp->mii) { - curr_link = mii_link_ok(&lp->mii_if); - } else { - ulong ioaddr = dev->base_addr; /* card base I/O address */ - curr_link = (lp->a.read_bcr(ioaddr, 4) != 0xc0); - } - if (!curr_link) { - if (prev_link || verbose) { - netif_carrier_off(dev); - if (netif_msg_link(lp)) - printk(KERN_INFO "%s: link down\n", dev->name); - } - if (lp->phycount > 1) { - curr_link = pcnet32_check_otherphy(dev); - prev_link = 0; - } - } else if (verbose || !prev_link) { - netif_carrier_on(dev); + struct pcnet32_private *lp = dev->priv; + int curr_link; + int prev_link = netif_carrier_ok(dev) ? 1 : 0; + u32 bcr9; + if (lp->mii) { - if (netif_msg_link(lp)) { - struct ethtool_cmd ecmd; - mii_ethtool_gset(&lp->mii_if, &ecmd); - printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n", - dev->name, - (ecmd.speed == SPEED_100) ? "100" : "10", - (ecmd.duplex == DUPLEX_FULL) ? "full" : "half"); - } - bcr9 = lp->a.read_bcr(dev->base_addr, 9); - if ((bcr9 & (1 << 0)) != lp->mii_if.full_duplex) { - if (lp->mii_if.full_duplex) - bcr9 |= (1 << 0); - else - bcr9 &= ~(1 << 0); - lp->a.write_bcr(dev->base_addr, 9, bcr9); - } + curr_link = mii_link_ok(&lp->mii_if); } else { - if (netif_msg_link(lp)) - printk(KERN_INFO "%s: link up\n", dev->name); + ulong ioaddr = dev->base_addr; /* card base I/O address */ + curr_link = (lp->a.read_bcr(ioaddr, 4) != 0xc0); + } + if (!curr_link) { + if (prev_link || verbose) { + netif_carrier_off(dev); + if (netif_msg_link(lp)) + printk(KERN_INFO "%s: link down\n", dev->name); + } + if (lp->phycount > 1) { + curr_link = pcnet32_check_otherphy(dev); + prev_link = 0; + } + } else if (verbose || !prev_link) { + netif_carrier_on(dev); + if (lp->mii) { + if (netif_msg_link(lp)) { + struct ethtool_cmd ecmd; + mii_ethtool_gset(&lp->mii_if, &ecmd); + printk(KERN_INFO + "%s: link up, %sMbps, %s-duplex\n", + dev->name, + (ecmd.speed == SPEED_100) ? "100" : "10", + (ecmd.duplex == + DUPLEX_FULL) ? "full" : "half"); + } + bcr9 = lp->a.read_bcr(dev->base_addr, 9); + if ((bcr9 & (1 << 0)) != lp->mii_if.full_duplex) { + if (lp->mii_if.full_duplex) + bcr9 |= (1 << 0); + else + bcr9 &= ~(1 << 0); + lp->a.write_bcr(dev->base_addr, 9, bcr9); + } + } else { + if (netif_msg_link(lp)) + printk(KERN_INFO "%s: link up\n", dev->name); + } } - } } /* @@ -2622,39 +2775,39 @@ static void pcnet32_check_media(struct net_device *dev, int verbose) static void pcnet32_watchdog(struct net_device *dev) { - struct pcnet32_private *lp = dev->priv; - unsigned long flags; + struct pcnet32_private *lp = dev->priv; + unsigned long flags; - /* Print the link status if it has changed */ - spin_lock_irqsave(&lp->lock, flags); - pcnet32_check_media(dev, 0); - spin_unlock_irqrestore(&lp->lock, flags); + /* Print the link status if it has changed */ + spin_lock_irqsave(&lp->lock, flags); + pcnet32_check_media(dev, 0); + spin_unlock_irqrestore(&lp->lock, flags); - mod_timer (&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); + mod_timer(&(lp->watchdog_timer), PCNET32_WATCHDOG_TIMEOUT); } static void __devexit pcnet32_remove_one(struct pci_dev *pdev) { - struct net_device *dev = pci_get_drvdata(pdev); - - if (dev) { - struct pcnet32_private *lp = dev->priv; - - unregister_netdev(dev); - pcnet32_free_ring(dev); - release_region(dev->base_addr, PCNET32_TOTAL_SIZE); - pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); - free_netdev(dev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - } + struct net_device *dev = pci_get_drvdata(pdev); + + if (dev) { + struct pcnet32_private *lp = dev->priv; + + unregister_netdev(dev); + pcnet32_free_ring(dev); + release_region(dev->base_addr, PCNET32_TOTAL_SIZE); + pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); + free_netdev(dev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); + } } static struct pci_driver pcnet32_driver = { - .name = DRV_NAME, - .probe = pcnet32_probe_pci, - .remove = __devexit_p(pcnet32_remove_one), - .id_table = pcnet32_pci_tbl, + .name = DRV_NAME, + .probe = pcnet32_probe_pci, + .remove = __devexit_p(pcnet32_remove_one), + .id_table = pcnet32_pci_tbl, }; /* An additional parameter that may be passed in... */ @@ -2665,9 +2818,11 @@ static int pcnet32_have_pci; module_param(debug, int, 0); MODULE_PARM_DESC(debug, DRV_NAME " debug level"); module_param(max_interrupt_work, int, 0); -MODULE_PARM_DESC(max_interrupt_work, DRV_NAME " maximum events handled per interrupt"); +MODULE_PARM_DESC(max_interrupt_work, + DRV_NAME " maximum events handled per interrupt"); module_param(rx_copybreak, int, 0); -MODULE_PARM_DESC(rx_copybreak, DRV_NAME " copy breakpoint for copy-only-tiny-frames"); +MODULE_PARM_DESC(rx_copybreak, + DRV_NAME " copy breakpoint for copy-only-tiny-frames"); module_param(tx_start_pt, int, 0); MODULE_PARM_DESC(tx_start_pt, DRV_NAME " transmit start point (0-3)"); module_param(pcnet32vlb, int, 0); @@ -2678,7 +2833,9 @@ module_param_array(full_duplex, int, NULL, 0); MODULE_PARM_DESC(full_duplex, DRV_NAME " full duplex setting(s) (1)"); /* Module Parameter for HomePNA cards added by Patrick Simmons, 2004 */ module_param_array(homepna, int, NULL, 0); -MODULE_PARM_DESC(homepna, DRV_NAME " mode for 79C978 cards (1 for HomePNA, 0 for Ethernet, default Ethernet"); +MODULE_PARM_DESC(homepna, + DRV_NAME + " mode for 79C978 cards (1 for HomePNA, 0 for Ethernet, default Ethernet"); MODULE_AUTHOR("Thomas Bogendoerfer"); MODULE_DESCRIPTION("Driver for PCnet32 and PCnetPCI based ethercards"); @@ -2688,44 +2845,44 @@ MODULE_LICENSE("GPL"); static int __init pcnet32_init_module(void) { - printk(KERN_INFO "%s", version); + printk(KERN_INFO "%s", version); - pcnet32_debug = netif_msg_init(debug, PCNET32_MSG_DEFAULT); + pcnet32_debug = netif_msg_init(debug, PCNET32_MSG_DEFAULT); - if ((tx_start_pt >= 0) && (tx_start_pt <= 3)) - tx_start = tx_start_pt; + if ((tx_start_pt >= 0) && (tx_start_pt <= 3)) + tx_start = tx_start_pt; - /* find the PCI devices */ - if (!pci_module_init(&pcnet32_driver)) - pcnet32_have_pci = 1; + /* find the PCI devices */ + if (!pci_module_init(&pcnet32_driver)) + pcnet32_have_pci = 1; - /* should we find any remaining VLbus devices ? */ - if (pcnet32vlb) - pcnet32_probe_vlbus(); + /* should we find any remaining VLbus devices ? */ + if (pcnet32vlb) + pcnet32_probe_vlbus(); - if (cards_found && (pcnet32_debug & NETIF_MSG_PROBE)) - printk(KERN_INFO PFX "%d cards_found.\n", cards_found); + if (cards_found && (pcnet32_debug & NETIF_MSG_PROBE)) + printk(KERN_INFO PFX "%d cards_found.\n", cards_found); - return (pcnet32_have_pci + cards_found) ? 0 : -ENODEV; + return (pcnet32_have_pci + cards_found) ? 0 : -ENODEV; } static void __exit pcnet32_cleanup_module(void) { - struct net_device *next_dev; - - while (pcnet32_dev) { - struct pcnet32_private *lp = pcnet32_dev->priv; - next_dev = lp->next; - unregister_netdev(pcnet32_dev); - pcnet32_free_ring(pcnet32_dev); - release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); - pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); - free_netdev(pcnet32_dev); - pcnet32_dev = next_dev; - } + struct net_device *next_dev; + + while (pcnet32_dev) { + struct pcnet32_private *lp = pcnet32_dev->priv; + next_dev = lp->next; + unregister_netdev(pcnet32_dev); + pcnet32_free_ring(pcnet32_dev); + release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); + pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); + free_netdev(pcnet32_dev); + pcnet32_dev = next_dev; + } - if (pcnet32_have_pci) - pci_unregister_driver(&pcnet32_driver); + if (pcnet32_have_pci) + pci_unregister_driver(&pcnet32_driver); } module_init(pcnet32_init_module); -- cgit v1.2.3 From 0b5bf225c06e62eb6066fc5b7ccf4f296356c503 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Tue, 21 Mar 2006 16:22:47 -0500 Subject: [netdrvr] pcnet32: other source formatting cleanups - undo some Lindent damage by indenting member names - remove history at top of .c file, this is stored in the kernel repo changelog (in greater detail, even). --- drivers/net/pcnet32.c | 228 ++++++++++++-------------------------------------- 1 file changed, 54 insertions(+), 174 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 86136101864..9595f74da93 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -155,126 +155,6 @@ static int homepna[MAX_UNITS]; * 16MB limitation and we don't need bounce buffers. */ -/* - * History: - * v0.01: Initial version - * only tested on Alpha Noname Board - * v0.02: changed IRQ handling for new interrupt scheme (dev_id) - * tested on a ASUS SP3G - * v0.10: fixed an odd problem with the 79C974 in a Compaq Deskpro XL - * looks like the 974 doesn't like stopping and restarting in a - * short period of time; now we do a reinit of the lance; the - * bug was triggered by doing ifconfig eth0 broadcast - * and hangs the machine (thanks to Klaus Liedl for debugging) - * v0.12: by suggestion from Donald Becker: Renamed driver to pcnet32, - * made it standalone (no need for lance.c) - * v0.13: added additional PCI detecting for special PCI devices (Compaq) - * v0.14: stripped down additional PCI probe (thanks to David C Niemi - * and sveneric@xs4all.nl for testing this on their Compaq boxes) - * v0.15: added 79C965 (VLB) probe - * added interrupt sharing for PCI chips - * v0.16: fixed set_multicast_list on Alpha machines - * v0.17: removed hack from dev.c; now pcnet32 uses ethif_probe in Space.c - * v0.19: changed setting of autoselect bit - * v0.20: removed additional Compaq PCI probe; there is now a working one - * in arch/i386/bios32.c - * v0.21: added endian conversion for ppc, from work by cort@cs.nmt.edu - * v0.22: added printing of status to ring dump - * v0.23: changed enet_statistics to net_devive_stats - * v0.90: added multicast filter - * added module support - * changed irq probe to new style - * added PCnetFast chip id - * added fix for receive stalls with Intel saturn chipsets - * added in-place rx skbs like in the tulip driver - * minor cleanups - * v0.91: added PCnetFast+ chip id - * back port to 2.0.x - * v1.00: added some stuff from Donald Becker's 2.0.34 version - * added support for byte counters in net_dev_stats - * v1.01: do ring dumps, only when debugging the driver - * increased the transmit timeout - * v1.02: fixed memory leak in pcnet32_init_ring() - * v1.10: workaround for stopped transmitter - * added port selection for modules - * detect special T1/E1 WAN card and setup port selection - * v1.11: fixed wrong checking of Tx errors - * v1.20: added check of return value kmalloc (cpeterso@cs.washington.edu) - * added save original kmalloc addr for freeing (mcr@solidum.com) - * added support for PCnetHome chip (joe@MIT.EDU) - * rewritten PCI card detection - * added dwio mode to get driver working on some PPC machines - * v1.21: added mii selection and mii ioctl - * v1.22: changed pci scanning code to make PPC people happy - * fixed switching to 32bit mode in pcnet32_open() (thanks - * to Michael Richard for noticing this one) - * added sub vendor/device id matching (thanks again to - * Michael Richard ) - * added chip id for 79c973/975 (thanks to Zach Brown ) - * v1.23 fixed small bug, when manual selecting MII speed/duplex - * v1.24 Applied Thomas' patch to use TxStartPoint and thus decrease TxFIFO - * underflows. Added tx_start_pt module parameter. Increased - * TX_RING_SIZE from 16 to 32. Added #ifdef'd code to use DXSUFLO - * for FAST[+] chipsets. - * v1.24ac Added SMP spinlocking - Alan Cox - * v1.25kf Added No Interrupt on successful Tx for some Tx's - * v1.26 Converted to pci_alloc_consistent, Jamey Hicks / George France - * - * - Fixed a few bugs, related to running the controller in 32bit mode. - * 23 Oct, 2000. Carsten Langgaard, carstenl@mips.com - * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. - * v1.26p Fix oops on rmmod+insmod; plug i/o resource leak - Paul Gortmaker - * v1.27 improved CSR/PROM address detection, lots of cleanups, - * new pcnet32vlb module option, HP-PARISC support, - * added module parameter descriptions, - * initial ethtool support - Helge Deller - * v1.27a Sun Feb 10 2002 Go Taniguchi - * use alloc_etherdev and register_netdev - * fix pci probe not increment cards_found - * FD auto negotiate error workaround for xSeries250 - * clean up and using new mii module - * v1.27b Sep 30 2002 Kent Yoder - * Added timer for cable connection state changes. - * v1.28 20 Feb 2004 Don Fry - * Jon Mason , Chinmay Albal - * Now uses ethtool_ops, netif_msg_* and generic_mii_ioctl. - * Fixes bogus 'Bus master arbitration failure', pci_[un]map_single - * length errors, and transmit hangs. Cleans up after errors in open. - * Jim Lewis added ethernet loopback test. - * Thomas Munck Steenholdt non-mii ioctl corrections. - * v1.29 6 Apr 2004 Jim Lewis added physical - * identification code (blink led's) and register dump. - * Don Fry added timer for 971/972 so skbufs don't remain on tx ring - * forever. - * v1.30 18 May 2004 Don Fry removed timer and Last Transmit Interrupt - * (ltint) as they added complexity and didn't give good throughput. - * v1.30a 22 May 2004 Don Fry limit frames received during interrupt. - * v1.30b 24 May 2004 Don Fry fix bogus tx carrier errors with 79c973, - * assisted by Bruce Penrod . - * v1.30c 25 May 2004 Don Fry added netif_wake_queue after pcnet32_restart. - * v1.30d 01 Jun 2004 Don Fry discard oversize rx packets. - * v1.30e 11 Jun 2004 Don Fry recover after fifo error and rx hang. - * v1.30f 16 Jun 2004 Don Fry cleanup IRQ to allow 0 and 1 for PCI, - * expanding on suggestions from Ralf Baechle , - * and Brian Murphy . - * v1.30g 22 Jun 2004 Patrick Simmons added option - * homepna for selecting HomePNA mode for PCNet/Home 79C978. - * v1.30h 24 Jun 2004 Don Fry correctly select auto, speed, duplex in bcr32. - * v1.30i 28 Jun 2004 Don Fry change to use module_param. - * v1.30j 29 Apr 2005 Don Fry fix skb/map leak with loopback test. - * v1.31 02 Sep 2005 Hubert WS Lin added set_ringparam(). - * v1.31a 12 Sep 2005 Hubert WS Lin set min ring size to 4 - * to allow loopback test to work unchanged. - * v1.31b 06 Oct 2005 Don Fry changed alloc_ring to show name of device - * if allocation fails - * v1.31c 01 Nov 2005 Don Fry Allied Telesyn 2700/2701 FX are 100Mbit only. - * Force 100Mbit FD if Auto (ASEL) is selected. - * See Bugzilla 2669 and 4551. - * v1.32 18 Mar2006 Thomas Bogendoerfer and Don Fry added Multi-Phy - * handling for supporting AT-270x FTX cards with FX and Tx PHYs. - * Philippe Seewer assisted with auto negotiation and testing. - */ - /* * Set the number of Tx and Rx buffers, using Log_2(# buffers). * Reasonable default values are 4 Tx buffers, and 16 Rx buffers. @@ -310,31 +190,31 @@ static int homepna[MAX_UNITS]; /* The PCNET32 Rx and Tx ring descriptors. */ struct pcnet32_rx_head { - u32 base; - s16 buf_length; - s16 status; - u32 msg_length; - u32 reserved; + u32 base; + s16 buf_length; + s16 status; + u32 msg_length; + u32 reserved; }; struct pcnet32_tx_head { - u32 base; - s16 length; - s16 status; - u32 misc; - u32 reserved; + u32 base; + s16 length; + s16 status; + u32 misc; + u32 reserved; }; /* The PCNET32 32-Bit initialization block, described in databook. */ struct pcnet32_init_block { - u16 mode; - u16 tlen_rlen; - u8 phys_addr[6]; - u16 reserved; - u32 filter[2]; + u16 mode; + u16 tlen_rlen; + u8 phys_addr[6]; + u16 reserved; + u32 filter[2]; /* Receive and transmit ring base, along with extra bits. */ - u32 rx_ring; - u32 tx_ring; + u32 rx_ring; + u32 tx_ring; }; /* PCnet32 access functions */ @@ -355,46 +235,46 @@ struct pcnet32_access { struct pcnet32_private { struct pcnet32_init_block init_block; /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ - struct pcnet32_rx_head *rx_ring; - struct pcnet32_tx_head *tx_ring; - dma_addr_t dma_addr; /* DMA address of beginning of this - object, returned by - pci_alloc_consistent */ - struct pci_dev *pci_dev; /* Pointer to the associated pci device - structure */ - const char *name; + struct pcnet32_rx_head *rx_ring; + struct pcnet32_tx_head *tx_ring; + dma_addr_t dma_addr;/* DMA address of beginning of this + object, returned by pci_alloc_consistent */ + struct pci_dev *pci_dev; + const char *name; /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff **tx_skbuff; - struct sk_buff **rx_skbuff; - dma_addr_t *tx_dma_addr; - dma_addr_t *rx_dma_addr; - struct pcnet32_access a; - spinlock_t lock; /* Guard lock */ - unsigned int cur_rx, cur_tx; /* The next free ring entry */ - unsigned int rx_ring_size; /* current rx ring size */ - unsigned int tx_ring_size; /* current tx ring size */ - unsigned int rx_mod_mask; /* rx ring modular mask */ - unsigned int tx_mod_mask; /* tx ring modular mask */ - unsigned short rx_len_bits; - unsigned short tx_len_bits; - dma_addr_t rx_ring_dma_addr; - dma_addr_t tx_ring_dma_addr; - unsigned int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - struct net_device_stats stats; - char tx_full; - char phycount; /* number of phys found */ - int options; - unsigned int shared_irq:1, /* shared irq possible */ - dxsuflo:1, /* disable transmit stop on uflo */ - mii:1; /* mii port available */ - struct net_device *next; - struct mii_if_info mii_if; - struct timer_list watchdog_timer; - struct timer_list blink_timer; - u32 msg_enable; /* debug message level */ + struct sk_buff **tx_skbuff; + struct sk_buff **rx_skbuff; + dma_addr_t *tx_dma_addr; + dma_addr_t *rx_dma_addr; + struct pcnet32_access a; + spinlock_t lock; /* Guard lock */ + unsigned int cur_rx, cur_tx; /* The next free ring entry */ + unsigned int rx_ring_size; /* current rx ring size */ + unsigned int tx_ring_size; /* current tx ring size */ + unsigned int rx_mod_mask; /* rx ring modular mask */ + unsigned int tx_mod_mask; /* tx ring modular mask */ + unsigned short rx_len_bits; + unsigned short tx_len_bits; + dma_addr_t rx_ring_dma_addr; + dma_addr_t tx_ring_dma_addr; + unsigned int dirty_rx, /* ring entries to be freed. */ + dirty_tx; + + struct net_device_stats stats; + char tx_full; + char phycount; /* number of phys found */ + int options; + unsigned int shared_irq:1, /* shared irq possible */ + dxsuflo:1, /* disable transmit stop on uflo */ + mii:1; /* mii port available */ + struct net_device *next; + struct mii_if_info mii_if; + struct timer_list watchdog_timer; + struct timer_list blink_timer; + u32 msg_enable; /* debug message level */ /* each bit indicates an available PHY */ - u32 phymask; + u32 phymask; }; static void pcnet32_probe_vlbus(void); -- cgit v1.2.3 From 18ec5c731271939acb414614e964c15c8ef52156 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Mon, 20 Mar 2006 17:10:17 +0000 Subject: [ARM] 3373/1: move uengine loader to arch/arm/common Patch from Lennert Buytenhek Move the uengine loader from arch/arm/mach-ixp2000 to arch/arm/common so that ixp23xx can use it too. Signed-off-by: Lennert Buytenhek Signed-off-by: Russell King --- drivers/net/ixp2000/enp2611.c | 2 +- drivers/net/ixp2000/ixpdev.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ixp2000/enp2611.c b/drivers/net/ixp2000/enp2611.c index d82651a97ba..6f7dce8eba5 100644 --- a/drivers/net/ixp2000/enp2611.c +++ b/drivers/net/ixp2000/enp2611.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include "ixpdev.h" diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 09f03f493be..77f104a005f 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include "ixp2400_rx.ucode" -- cgit v1.2.3 From 9e6b48732d53bd986178bca3bce18d2329e4b0ca Mon Sep 17 00:00:00 2001 From: James Ring Date: Wed, 22 Mar 2006 00:51:11 +0100 Subject: Fix spelling in E1000_DISABLE_PACKET_SPLIT Kconfig description Signed-off-by: Adrian Bunk --- drivers/net/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e0b11095b9d..00993e8ba58 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -1914,7 +1914,7 @@ config E1000_DISABLE_PACKET_SPLIT depends on E1000 help Say Y here if you want to use the legacy receive path for PCI express - hadware. + hardware. If in doubt, say N. -- cgit v1.2.3 From caf636c760b33c72ebf018ff03c1b0d79ea6656a Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 22 Mar 2006 01:05:31 -0800 Subject: [TG3]: Fix SRAM access during tg3_init_one() 5700 and 5701 will not return correct SRAM data when the chip is in D3hot power state. tg3_get_eeprom_hw_cfg() must first put the device in D0 before reading SRAM. Thanks to Thomas Chenault at Dell for noticing this problem. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index e03d1ae50c3..cb687fcaae1 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -9436,12 +9436,18 @@ static inline struct subsys_tbl_ent *lookup_by_subsys(struct tg3 *tp) return NULL; } -/* Since this function may be called in D3-hot power state during - * tg3_init_one(), only config cycles are allowed. - */ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) { u32 val; + u16 pmcsr; + + /* On some early chips the SRAM cannot be accessed in D3hot state, + * so need make sure we're in D0. + */ + pci_read_config_word(tp->pdev, tp->pm_cap + PCI_PM_CTRL, &pmcsr); + pmcsr &= ~PCI_PM_CTRL_STATE_MASK; + pci_write_config_word(tp->pdev, tp->pm_cap + PCI_PM_CTRL, pmcsr); + msleep(1); /* Make sure register accesses (indirect or otherwise) * will function correctly. -- cgit v1.2.3 From 15c3b696101992c4d69962325f0e91647164427f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Wed, 22 Mar 2006 01:06:52 -0800 Subject: [TG3]: Skip phy power down on some devices Some PHYs should not be powered down in tg3_set_power_state() because of bugs or other hardware limitations. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index cb687fcaae1..f1d9a07bb88 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -1148,6 +1148,19 @@ static int tg3_halt_cpu(struct tg3 *, u32); static int tg3_nvram_lock(struct tg3 *); static void tg3_nvram_unlock(struct tg3 *); +static void tg3_power_down_phy(struct tg3 *tp) +{ + /* The PHY should not be powered down on some chips because + * of bugs. + */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780 && + (tp->tg3_flags2 & TG3_FLG2_MII_SERDES))) + return; + tg3_writephy(tp, MII_BMCR, BMCR_PDOWN); +} + static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) { u32 misc_host_ctrl; @@ -1327,8 +1340,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) tg3_writephy(tp, MII_TG3_EXT_CTRL, MII_TG3_EXT_CTRL_FORCE_LED_OFF); tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2); - if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700) - tg3_writephy(tp, MII_BMCR, BMCR_PDOWN); + tg3_power_down_phy(tp); } } -- cgit v1.2.3 From 056755f4d73d49b4adcbb8ecdaf75138cf166bd3 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Wed, 22 Mar 2006 01:07:53 -0800 Subject: [TG3]: Bump driver version and reldate. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index f1d9a07bb88..88829eb9568 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -69,8 +69,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.52" -#define DRV_MODULE_RELDATE "Mar 06, 2006" +#define DRV_MODULE_VERSION "3.53" +#define DRV_MODULE_RELDATE "Mar 22, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3 From d97381702d3a2f917cfe935fbca1e850a37b984b Mon Sep 17 00:00:00 2001 From: Jens Osterkamp Date: Tue, 21 Mar 2006 22:53:47 -0800 Subject: [PATCH] fix spidernet build issue Signed-off-by: Jens Osterkamp Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 00e72b12fb9..b90468aea07 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -58,8 +58,8 @@ obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_FEALNX) += fealnx.o obj-$(CONFIG_TIGON3) += tg3.o obj-$(CONFIG_BNX2) += bnx2.o -spidernet-y += spider_net.o spider_net_ethtool.o sungem_phy.o -obj-$(CONFIG_SPIDER_NET) += spidernet.o +spidernet-y += spider_net.o spider_net_ethtool.o +obj-$(CONFIG_SPIDER_NET) += spidernet.o sungem_phy.o obj-$(CONFIG_TC35815) += tc35815.o obj-$(CONFIG_SKGE) += skge.o obj-$(CONFIG_SKY2) += sky2.o -- cgit v1.2.3 From c2d3d4b938d1a8df4fd4db73427009dfb9e8b225 Mon Sep 17 00:00:00 2001 From: Sergei Shtylylov Date: Tue, 21 Mar 2006 22:53:52 -0800 Subject: [PATCH] AMD Au1xx0: fix Ethernet TX stats With Au1xx0 Ethernet driver, TX bytes/packets always remain zero. The problem seems to be that when packet has been transmitted, the length word in DMA buffer is zero. The patch updates the TX stats when a buffer is fed to DMA. The initial 2.4 patch was posted to linux-mips@linux-mips.org by Thomas Lange 21 Jan 2005. Signed-off-by: Thomas Lange Signed-off-by: Sergei Shtylyov Cc: Jordan Crouse Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/au1000_eth.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index cd0b1dccfb6..1363083b4d8 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -90,8 +90,6 @@ static void au1000_tx_timeout(struct net_device *); static int au1000_set_config(struct net_device *dev, struct ifmap *map); static void set_rx_mode(struct net_device *); static struct net_device_stats *au1000_get_stats(struct net_device *); -static inline void update_tx_stats(struct net_device *, u32, u32); -static inline void update_rx_stats(struct net_device *, u32); static void au1000_timer(unsigned long); static int au1000_ioctl(struct net_device *, struct ifreq *, int); static int mdio_read(struct net_device *, int, int); @@ -1825,16 +1823,11 @@ static void __exit au1000_cleanup_module(void) } } - -static inline void -update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) +static void update_tx_stats(struct net_device *dev, u32 status) { struct au1000_private *aup = (struct au1000_private *) dev->priv; struct net_device_stats *ps = &aup->stats; - ps->tx_packets++; - ps->tx_bytes += pkt_len; - if (status & TX_FRAME_ABORTED) { if (dev->if_port == IF_PORT_100BASEFX) { if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) { @@ -1867,7 +1860,7 @@ static void au1000_tx_ack(struct net_device *dev) ptxd = aup->tx_dma_ring[aup->tx_tail]; while (ptxd->buff_stat & TX_T_DONE) { - update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff); + update_tx_stats(dev, ptxd->status); ptxd->buff_stat &= ~TX_T_DONE; ptxd->len = 0; au_sync(); @@ -1889,6 +1882,7 @@ static void au1000_tx_ack(struct net_device *dev) static int au1000_tx(struct sk_buff *skb, struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct net_device_stats *ps = &aup->stats; volatile tx_dma_t *ptxd; u32 buff_stat; db_dest_t *pDB; @@ -1908,7 +1902,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) return 1; } else if (buff_stat & TX_T_DONE) { - update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff); + update_tx_stats(dev, ptxd->status); ptxd->len = 0; } @@ -1928,6 +1922,9 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) else ptxd->len = skb->len; + ps->tx_packets++; + ps->tx_bytes += ptxd->len; + ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE; au_sync(); dev_kfree_skb(skb); @@ -1936,7 +1933,6 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) return 0; } - static inline void update_rx_stats(struct net_device *dev, u32 status) { struct au1000_private *aup = (struct au1000_private *) dev->priv; -- cgit v1.2.3 From eadfa7ddca98b0430b8b666e0344ab1d559389c8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 22 Mar 2006 10:38:45 -0800 Subject: [PATCH] sky2: more ethtool stats Expose all the available hardware statistics via ethtool. And cleanup some of the statistics definitions. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 27 +++++++++++++++++---- drivers/net/sky2.h | 71 +++++++++++++++++++++++++++--------------------------- 2 files changed, 57 insertions(+), 41 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index f08fe6c884b..36db93811ac 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2478,17 +2478,34 @@ static const struct sky2_stat { { "rx_unicast", GM_RXF_UC_OK }, { "tx_mac_pause", GM_TXF_MPAUSE }, { "rx_mac_pause", GM_RXF_MPAUSE }, - { "collisions", GM_TXF_SNG_COL }, + { "collisions", GM_TXF_COL }, { "late_collision",GM_TXF_LAT_COL }, { "aborted", GM_TXF_ABO_COL }, + { "single_collisions", GM_TXF_SNG_COL }, { "multi_collisions", GM_TXF_MUL_COL }, - { "fifo_underrun", GM_TXE_FIFO_UR }, - { "fifo_overflow", GM_RXE_FIFO_OV }, - { "rx_toolong", GM_RXF_LNG_ERR }, - { "rx_jabber", GM_RXF_JAB_PKT }, + + { "rx_short", GM_RXE_SHT }, { "rx_runt", GM_RXE_FRAG }, + { "rx_64_byte_packets", GM_RXF_64B }, + { "rx_65_to_127_byte_packets", GM_RXF_127B }, + { "rx_128_to_255_byte_packets", GM_RXF_255B }, + { "rx_256_to_511_byte_packets", GM_RXF_511B }, + { "rx_512_to_1023_byte_packets", GM_RXF_1023B }, + { "rx_1024_to_1518_byte_packets", GM_RXF_1518B }, + { "rx_1518_to_max_byte_packets", GM_RXF_MAX_SZ }, { "rx_too_long", GM_RXF_LNG_ERR }, + { "rx_fifo_overflow", GM_RXE_FIFO_OV }, + { "rx_jabber", GM_RXF_JAB_PKT }, { "rx_fcs_error", GM_RXF_FCS_ERR }, + + { "tx_64_byte_packets", GM_TXF_64B }, + { "tx_65_to_127_byte_packets", GM_TXF_127B }, + { "tx_128_to_255_byte_packets", GM_TXF_255B }, + { "tx_256_to_511_byte_packets", GM_TXF_511B }, + { "tx_512_to_1023_byte_packets", GM_TXF_1023B }, + { "tx_1024_to_1518_byte_packets", GM_TXF_1518B }, + { "tx_1519_to_max_byte_packets", GM_TXF_MAX_SZ }, + { "tx_fifo_underrun", GM_TXE_FIFO_UR }, }; static u32 sky2_get_rx_csum(struct net_device *dev) diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index d63cd5a1b71..2838f661b39 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1373,23 +1373,23 @@ enum { GM_SMI_CTRL = 0x0080, /* 16 bit r/w SMI Control Register */ GM_SMI_DATA = 0x0084, /* 16 bit r/w SMI Data Register */ GM_PHY_ADDR = 0x0088, /* 16 bit r/w GPHY Address Register */ +/* MIB Counters */ + GM_MIB_CNT_BASE = 0x0100, /* Base Address of MIB Counters */ + GM_MIB_CNT_SIZE = 256, }; -/* MIB Counters */ -#define GM_MIB_CNT_BASE 0x0100 /* Base Address of MIB Counters */ -#define GM_MIB_CNT_SIZE 44 /* Number of MIB Counters */ /* * MIB Counters base address definitions (low word) - * use offset 4 for access to high word (32 bit r/o) */ enum { - GM_RXF_UC_OK = GM_MIB_CNT_BASE + 0, /* Unicast Frames Received OK */ + GM_RXF_UC_OK = GM_MIB_CNT_BASE + 0, /* Unicast Frames Received OK */ GM_RXF_BC_OK = GM_MIB_CNT_BASE + 8, /* Broadcast Frames Received OK */ GM_RXF_MPAUSE = GM_MIB_CNT_BASE + 16, /* Pause MAC Ctrl Frames Received */ GM_RXF_MC_OK = GM_MIB_CNT_BASE + 24, /* Multicast Frames Received OK */ GM_RXF_FCS_ERR = GM_MIB_CNT_BASE + 32, /* Rx Frame Check Seq. Error */ - /* GM_MIB_CNT_BASE + 40: reserved */ + GM_RXO_OK_LO = GM_MIB_CNT_BASE + 48, /* Octets Received OK Low */ GM_RXO_OK_HI = GM_MIB_CNT_BASE + 56, /* Octets Received OK High */ GM_RXO_ERR_LO = GM_MIB_CNT_BASE + 64, /* Octets Received Invalid Low */ @@ -1397,37 +1397,36 @@ enum { GM_RXF_SHT = GM_MIB_CNT_BASE + 80, /* Frames <64 Byte Received OK */ GM_RXE_FRAG = GM_MIB_CNT_BASE + 88, /* Frames <64 Byte Received with FCS Err */ GM_RXF_64B = GM_MIB_CNT_BASE + 96, /* 64 Byte Rx Frame */ - GM_RXF_127B = GM_MIB_CNT_BASE + 104, /* 65-127 Byte Rx Frame */ - GM_RXF_255B = GM_MIB_CNT_BASE + 112, /* 128-255 Byte Rx Frame */ - GM_RXF_511B = GM_MIB_CNT_BASE + 120, /* 256-511 Byte Rx Frame */ - GM_RXF_1023B = GM_MIB_CNT_BASE + 128, /* 512-1023 Byte Rx Frame */ - GM_RXF_1518B = GM_MIB_CNT_BASE + 136, /* 1024-1518 Byte Rx Frame */ - GM_RXF_MAX_SZ = GM_MIB_CNT_BASE + 144, /* 1519-MaxSize Byte Rx Frame */ - GM_RXF_LNG_ERR = GM_MIB_CNT_BASE + 152, /* Rx Frame too Long Error */ - GM_RXF_JAB_PKT = GM_MIB_CNT_BASE + 160, /* Rx Jabber Packet Frame */ - /* GM_MIB_CNT_BASE + 168: reserved */ - GM_RXE_FIFO_OV = GM_MIB_CNT_BASE + 176, /* Rx FIFO overflow Event */ - /* GM_MIB_CNT_BASE + 184: reserved */ - GM_TXF_UC_OK = GM_MIB_CNT_BASE + 192, /* Unicast Frames Xmitted OK */ - GM_TXF_BC_OK = GM_MIB_CNT_BASE + 200, /* Broadcast Frames Xmitted OK */ - GM_TXF_MPAUSE = GM_MIB_CNT_BASE + 208, /* Pause MAC Ctrl Frames Xmitted */ - GM_TXF_MC_OK = GM_MIB_CNT_BASE + 216, /* Multicast Frames Xmitted OK */ - GM_TXO_OK_LO = GM_MIB_CNT_BASE + 224, /* Octets Transmitted OK Low */ - GM_TXO_OK_HI = GM_MIB_CNT_BASE + 232, /* Octets Transmitted OK High */ - GM_TXF_64B = GM_MIB_CNT_BASE + 240, /* 64 Byte Tx Frame */ - GM_TXF_127B = GM_MIB_CNT_BASE + 248, /* 65-127 Byte Tx Frame */ - GM_TXF_255B = GM_MIB_CNT_BASE + 256, /* 128-255 Byte Tx Frame */ - GM_TXF_511B = GM_MIB_CNT_BASE + 264, /* 256-511 Byte Tx Frame */ - GM_TXF_1023B = GM_MIB_CNT_BASE + 272, /* 512-1023 Byte Tx Frame */ - GM_TXF_1518B = GM_MIB_CNT_BASE + 280, /* 1024-1518 Byte Tx Frame */ - GM_TXF_MAX_SZ = GM_MIB_CNT_BASE + 288, /* 1519-MaxSize Byte Tx Frame */ - - GM_TXF_COL = GM_MIB_CNT_BASE + 304, /* Tx Collision */ - GM_TXF_LAT_COL = GM_MIB_CNT_BASE + 312, /* Tx Late Collision */ - GM_TXF_ABO_COL = GM_MIB_CNT_BASE + 320, /* Tx aborted due to Exces. Col. */ - GM_TXF_MUL_COL = GM_MIB_CNT_BASE + 328, /* Tx Multiple Collision */ - GM_TXF_SNG_COL = GM_MIB_CNT_BASE + 336, /* Tx Single Collision */ - GM_TXE_FIFO_UR = GM_MIB_CNT_BASE + 344, /* Tx FIFO Underrun Event */ + GM_RXF_127B = GM_MIB_CNT_BASE + 104,/* 65-127 Byte Rx Frame */ + GM_RXF_255B = GM_MIB_CNT_BASE + 112,/* 128-255 Byte Rx Frame */ + GM_RXF_511B = GM_MIB_CNT_BASE + 120,/* 256-511 Byte Rx Frame */ + GM_RXF_1023B = GM_MIB_CNT_BASE + 128,/* 512-1023 Byte Rx Frame */ + GM_RXF_1518B = GM_MIB_CNT_BASE + 136,/* 1024-1518 Byte Rx Frame */ + GM_RXF_MAX_SZ = GM_MIB_CNT_BASE + 144,/* 1519-MaxSize Byte Rx Frame */ + GM_RXF_LNG_ERR = GM_MIB_CNT_BASE + 152,/* Rx Frame too Long Error */ + GM_RXF_JAB_PKT = GM_MIB_CNT_BASE + 160,/* Rx Jabber Packet Frame */ + + GM_RXE_FIFO_OV = GM_MIB_CNT_BASE + 176,/* Rx FIFO overflow Event */ + GM_TXF_UC_OK = GM_MIB_CNT_BASE + 192,/* Unicast Frames Xmitted OK */ + GM_TXF_BC_OK = GM_MIB_CNT_BASE + 200,/* Broadcast Frames Xmitted OK */ + GM_TXF_MPAUSE = GM_MIB_CNT_BASE + 208,/* Pause MAC Ctrl Frames Xmitted */ + GM_TXF_MC_OK = GM_MIB_CNT_BASE + 216,/* Multicast Frames Xmitted OK */ + GM_TXO_OK_LO = GM_MIB_CNT_BASE + 224,/* Octets Transmitted OK Low */ + GM_TXO_OK_HI = GM_MIB_CNT_BASE + 232,/* Octets Transmitted OK High */ + GM_TXF_64B = GM_MIB_CNT_BASE + 240,/* 64 Byte Tx Frame */ + GM_TXF_127B = GM_MIB_CNT_BASE + 248,/* 65-127 Byte Tx Frame */ + GM_TXF_255B = GM_MIB_CNT_BASE + 256,/* 128-255 Byte Tx Frame */ + GM_TXF_511B = GM_MIB_CNT_BASE + 264,/* 256-511 Byte Tx Frame */ + GM_TXF_1023B = GM_MIB_CNT_BASE + 272,/* 512-1023 Byte Tx Frame */ + GM_TXF_1518B = GM_MIB_CNT_BASE + 280,/* 1024-1518 Byte Tx Frame */ + GM_TXF_MAX_SZ = GM_MIB_CNT_BASE + 288,/* 1519-MaxSize Byte Tx Frame */ + + GM_TXF_COL = GM_MIB_CNT_BASE + 304,/* Tx Collision */ + GM_TXF_LAT_COL = GM_MIB_CNT_BASE + 312,/* Tx Late Collision */ + GM_TXF_ABO_COL = GM_MIB_CNT_BASE + 320,/* Tx aborted due to Exces. Col. */ + GM_TXF_MUL_COL = GM_MIB_CNT_BASE + 328,/* Tx Multiple Collision */ + GM_TXF_SNG_COL = GM_MIB_CNT_BASE + 336,/* Tx Single Collision */ + GM_TXE_FIFO_UR = GM_MIB_CNT_BASE + 344,/* Tx FIFO Underrun Event */ }; /* GMAC Bit Definitions */ -- cgit v1.2.3 From 494aced2cda34c186083f7d53c419426eea3d584 Mon Sep 17 00:00:00 2001 From: Artur Skawina Date: Tue, 21 Mar 2006 22:04:36 +0100 Subject: [PATCH] sis900 adm7001 PHY support this patch is required to get a SIS964 based motherboard ethernet working (FSC D1875) (picking the #1 transceiver, instead of the last one, in case no known ones were found might be a better default, and would have worked in this case too) Signed-off-by: Artur Skawina Signed-off-by: Jeff Garzik --- drivers/net/sis900.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index a1cb07cdb60..253440a9802 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -128,6 +128,7 @@ static const struct mii_chip_info { { "SiS 900 Internal MII PHY", 0x001d, 0x8000, LAN }, { "SiS 7014 Physical Layer Solution", 0x0016, 0xf830, LAN }, { "Altimata AC101LF PHY", 0x0022, 0x5520, LAN }, + { "ADM 7001 LAN PHY", 0x002e, 0xcc60, LAN }, { "AMD 79C901 10BASE-T PHY", 0x0000, 0x6B70, LAN }, { "AMD 79C901 HomePNA PHY", 0x0000, 0x6B90, HOME}, { "ICS LAN PHY", 0x0015, 0xF440, LAN }, -- cgit v1.2.3 From 5185c7c20a4b88892f868ad8d92d1b640b1edba9 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Wed, 22 Mar 2006 22:30:34 +0100 Subject: [PATCH] Use after free in net/tulip/de2104x.c hi, this fixes coverity bug #912, where skb is freed first, and dereferenced a few lines later with skb->len. Signed-off-by: Eric Sesterhenn Signed-off-by: Jeff Garzik --- drivers/net/tulip/de2104x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 6299e186c73..e3dd144d326 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1327,11 +1327,11 @@ static void de_clean_rings (struct de_private *de) struct sk_buff *skb = de->tx_skb[i].skb; if ((skb) && (skb != DE_DUMMY_SKB)) { if (skb != DE_SETUP_SKB) { - dev_kfree_skb(skb); de->net_stats.tx_dropped++; pci_unmap_single(de->pdev, de->tx_skb[i].mapping, skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb(skb); } else { pci_unmap_single(de->pdev, de->tx_skb[i].mapping, -- cgit v1.2.3 From 6a6bbd29a0284c1b9d33c324ba85f3ebb5509589 Mon Sep 17 00:00:00 2001 From: Eric Sesterhenn Date: Wed, 22 Mar 2006 22:49:48 +0100 Subject: [PATCH] Use of uninitialized variable in drivers/net/depca.c hi, this fixes coverity bug #888, where the variable dev is used uninitialized. I assume the programmer meant to use mdev, which is initialized. Compile tested only. Signed-off-by: Eric Sesterhenn Signed-off-by: Jeff Garzik --- drivers/net/depca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/depca.c b/drivers/net/depca.c index 03804cc38be..0941d40f046 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -1412,7 +1412,7 @@ static int __init depca_mca_probe(struct device *device) irq = 11; break; default: - printk("%s: mca_probe IRQ error. You should never get here (%d).\n", dev->name, where); + printk("%s: mca_probe IRQ error. You should never get here (%d).\n", mdev->name, where); return -EINVAL; } -- cgit v1.2.3 From bf5295bba804a6aead9bc1c0d5970173a9d4e08e Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 23 Mar 2006 01:11:56 -0800 Subject: [BNX2]: Fix link change handling Fix some link-related problems by doing a coalesce_now after link change interrupt to flush out the transient link status. To facilitate this, the host coalesce cmd register value is cached in the device structure. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 29 +++++++++++++++++------------ drivers/net/bnx2.h | 1 + 2 files changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 7d213707008..c56888e6635 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -313,8 +313,6 @@ bnx2_disable_int(struct bnx2 *bp) static void bnx2_enable_int(struct bnx2 *bp) { - u32 val; - REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | BNX2_PCICFG_INT_ACK_CMD_MASK_INT | bp->last_status_idx); @@ -322,8 +320,7 @@ bnx2_enable_int(struct bnx2 *bp) REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx); - val = REG_RD(bp, BNX2_HC_COMMAND); - REG_WR(bp, BNX2_HC_COMMAND, val | BNX2_HC_COMMAND_COAL_NOW); + REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW); } static void @@ -1926,6 +1923,13 @@ bnx2_poll(struct net_device *dev, int *budget) spin_lock(&bp->phy_lock); bnx2_phy_int(bp); spin_unlock(&bp->phy_lock); + + /* This is needed to take care of transient status + * during link changes. + */ + REG_WR(bp, BNX2_HC_COMMAND, + bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); + REG_RD(bp, BNX2_HC_COMMAND); } if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) @@ -3307,6 +3311,8 @@ bnx2_init_chip(struct bnx2 *bp) udelay(20); + bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND); + return rc; } @@ -3746,7 +3752,6 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) struct sk_buff *skb, *rx_skb; unsigned char *packet; u16 rx_start_idx, rx_idx; - u32 val; dma_addr_t map; struct tx_bd *txbd; struct sw_bd *rx_buf; @@ -3777,8 +3782,9 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) map = pci_map_single(bp->pdev, skb->data, pkt_size, PCI_DMA_TODEVICE); - val = REG_RD(bp, BNX2_HC_COMMAND); - REG_WR(bp, BNX2_HC_COMMAND, val | BNX2_HC_COMMAND_COAL_NOW_WO_INT); + REG_WR(bp, BNX2_HC_COMMAND, + bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); + REG_RD(bp, BNX2_HC_COMMAND); udelay(5); @@ -3802,8 +3808,9 @@ bnx2_run_loopback(struct bnx2 *bp, int loopback_mode) udelay(100); - val = REG_RD(bp, BNX2_HC_COMMAND); - REG_WR(bp, BNX2_HC_COMMAND, val | BNX2_HC_COMMAND_COAL_NOW_WO_INT); + REG_WR(bp, BNX2_HC_COMMAND, + bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); + REG_RD(bp, BNX2_HC_COMMAND); udelay(5); @@ -3939,7 +3946,6 @@ static int bnx2_test_intr(struct bnx2 *bp) { int i; - u32 val; u16 status_idx; if (!netif_running(bp->dev)) @@ -3948,8 +3954,7 @@ bnx2_test_intr(struct bnx2 *bp) status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff; /* This register is not touched during run-time. */ - val = REG_RD(bp, BNX2_HC_COMMAND); - REG_WR(bp, BNX2_HC_COMMAND, val | BNX2_HC_COMMAND_COAL_NOW); + REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW); REG_RD(bp, BNX2_HC_COMMAND); for (i = 0; i < 10; i++) { diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index fd4b7f2eb47..18bc0919cc9 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -4038,6 +4038,7 @@ struct bnx2 { struct statistics_block *stats_blk; dma_addr_t stats_blk_mapping; + u32 hc_cmd; u32 rx_mode; u16 req_line_speed; -- cgit v1.2.3 From 0f31f99446270e66c6f18c7d87aadd7db1dad214 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 23 Mar 2006 01:12:38 -0800 Subject: [BNX2]: Combine small mem allocations Combine two small (56 byte and 320 byte) pci consistent memory allocations into one allocation. Jeff Garzik suggested to store the combined size in the bp structure for later use when freeing the memory. Use kzalloc() instead of kmalloc() + memset(). Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 34 +++++++++++++++------------------- drivers/net/bnx2.h | 2 ++ 2 files changed, 17 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index c56888e6635..8ce5ae84c83 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -359,15 +359,11 @@ bnx2_free_mem(struct bnx2 *bp) { int i; - if (bp->stats_blk) { - pci_free_consistent(bp->pdev, sizeof(struct statistics_block), - bp->stats_blk, bp->stats_blk_mapping); - bp->stats_blk = NULL; - } if (bp->status_blk) { - pci_free_consistent(bp->pdev, sizeof(struct status_block), + pci_free_consistent(bp->pdev, bp->status_stats_size, bp->status_blk, bp->status_blk_mapping); bp->status_blk = NULL; + bp->stats_blk = NULL; } if (bp->tx_desc_ring) { pci_free_consistent(bp->pdev, @@ -392,14 +388,13 @@ bnx2_free_mem(struct bnx2 *bp) static int bnx2_alloc_mem(struct bnx2 *bp) { - int i; + int i, status_blk_size; - bp->tx_buf_ring = kmalloc(sizeof(struct sw_bd) * TX_DESC_CNT, - GFP_KERNEL); + bp->tx_buf_ring = kzalloc(sizeof(struct sw_bd) * TX_DESC_CNT, + GFP_KERNEL); if (bp->tx_buf_ring == NULL) return -ENOMEM; - memset(bp->tx_buf_ring, 0, sizeof(struct sw_bd) * TX_DESC_CNT); bp->tx_desc_ring = pci_alloc_consistent(bp->pdev, sizeof(struct tx_bd) * TX_DESC_CNT, @@ -425,21 +420,22 @@ bnx2_alloc_mem(struct bnx2 *bp) } - bp->status_blk = pci_alloc_consistent(bp->pdev, - sizeof(struct status_block), + /* Combine status and statistics blocks into one allocation. */ + status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block)); + bp->status_stats_size = status_blk_size + + sizeof(struct statistics_block); + + bp->status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size, &bp->status_blk_mapping); if (bp->status_blk == NULL) goto alloc_mem_err; - memset(bp->status_blk, 0, sizeof(struct status_block)); + memset(bp->status_blk, 0, bp->status_stats_size); - bp->stats_blk = pci_alloc_consistent(bp->pdev, - sizeof(struct statistics_block), - &bp->stats_blk_mapping); - if (bp->stats_blk == NULL) - goto alloc_mem_err; + bp->stats_blk = (void *) ((unsigned long) bp->status_blk + + status_blk_size); - memset(bp->stats_blk, 0, sizeof(struct statistics_block)); + bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size; return 0; diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 18bc0919cc9..5d132b00e8f 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -4083,6 +4083,8 @@ struct bnx2 { struct flash_spec *flash_info; u32 flash_size; + + int status_stats_size; }; static u32 bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset); -- cgit v1.2.3 From f2a4f05216e95f3b8c06b858abc0fe9a77500816 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 23 Mar 2006 01:13:12 -0800 Subject: [BNX2]: Move .h files to bnx2.c Move all #include <> from bnx2.h to bnx2.c. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 40 ++++++++++++++++++++++++++++++++++++++++ drivers/net/bnx2.h | 40 ---------------------------------------- 2 files changed, 40 insertions(+), 40 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 8ce5ae84c83..3f2eaf52d19 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -9,6 +9,46 @@ * Written by: Michael Chan (mchan@broadcom.com) */ +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef NETIF_F_HW_VLAN_TX +#include +#define BCM_VLAN 1 +#endif +#ifdef NETIF_F_TSO +#include +#include +#include +#define BCM_TSO 1 +#endif +#include +#include +#include + #include "bnx2.h" #include "bnx2_fw.h" diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 5d132b00e8f..60598849acd 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -13,46 +13,6 @@ #ifndef BNX2_H #define BNX2_H -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef NETIF_F_HW_VLAN_TX -#include -#define BCM_VLAN 1 -#endif -#ifdef NETIF_F_TSO -#include -#include -#include -#define BCM_TSO 1 -#endif -#include -#include -#include - /* Hardware data structures and register definitions automatically * generated from RTL code. Do not modify. */ -- cgit v1.2.3 From 29b12174ac14f110225d6d9ebb66c30df5023baf Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 23 Mar 2006 01:13:43 -0800 Subject: [BNX2]: Separate tx producer and consumer fields Put the tx producer and consumer fields in separate cache lines in the device structure, similar to the VJ net channel queue structure. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 1 + drivers/net/bnx2.h | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 3f2eaf52d19..6ccacb5f254 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -48,6 +48,7 @@ #include #include #include +#include #include "bnx2.h" #include "bnx2_fw.h" diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 60598849acd..b87925f6a22 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -3877,15 +3877,17 @@ struct bnx2 { #define USING_MSI_FLAG 0x20 #define ASF_ENABLE_FLAG 0x40 - struct tx_bd *tx_desc_ring; - struct sw_bd *tx_buf_ring; - u32 tx_prod_bseq; - u16 tx_prod; - u16 tx_cons; - int tx_ring_size; - - u16 hw_tx_cons; - u16 hw_rx_cons; + /* Put tx producer and consumer fields in separate cache lines. */ + + u32 tx_prod_bseq __attribute__((aligned(L1_CACHE_BYTES))); + u16 tx_prod; + + struct tx_bd *tx_desc_ring; + struct sw_bd *tx_buf_ring; + int tx_ring_size; + + u16 tx_cons __attribute__((aligned(L1_CACHE_BYTES))); + u16 hw_tx_cons; #ifdef BCM_VLAN struct vlan_group *vlgrp; @@ -3899,6 +3901,7 @@ struct bnx2 { u32 rx_prod_bseq; u16 rx_prod; u16 rx_cons; + u16 hw_rx_cons; u32 rx_csum; -- cgit v1.2.3 From 5e2e71141ca93a3e2543966ced6a6077d4fb8fd8 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 23 Mar 2006 01:14:09 -0800 Subject: [BNX2]: Update version and reldate Update version to 1.4.39. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/bnx2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 6ccacb5f254..2671da20a49 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -55,8 +55,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.4.38" -#define DRV_MODULE_RELDATE "February 10, 2006" +#define DRV_MODULE_VERSION "1.4.39" +#define DRV_MODULE_RELDATE "March 22, 2006" #define RUN_AT(x) (jiffies + (x)) -- cgit v1.2.3 From af36e6b6d7f4ad7a5ccfd14dfa71ec941255f93d Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 23 Mar 2006 01:28:06 -0800 Subject: [TG3]: Add 5755 support Add support for new chip 5755 which is very similar to 5787. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 37 +++++++++++++++++++++++++++++++------ drivers/net/tg3.h | 6 +++++- 2 files changed, 36 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 88829eb9568..c69c8df088d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -225,6 +225,10 @@ static struct pci_device_id tg3_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755M, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M, @@ -4557,6 +4561,7 @@ static int tg3_chip_reset(struct tg3 *tp) } if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) tw32(GRC_FASTBOOT_PC, 0); @@ -6152,6 +6157,9 @@ static int tg3_reset_hw(struct tg3 *tp) gpio_mask |= GRC_LCLCTRL_GPIO_OE3 | GRC_LCLCTRL_GPIO_OUTPUT3; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) + gpio_mask |= GRC_LCLCTRL_GPIO_UART_SEL; + tp->grc_local_ctrl |= tr32(GRC_LOCAL_CTRL) & gpio_mask; /* GPIO1 must be driven high for eeprom write protect */ @@ -6191,7 +6199,8 @@ static int tg3_reset_hw(struct tg3 *tp) } /* Enable host coalescing bug fix */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) || + (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)) val |= (1 << 29); tw32_f(WDMAC_MODE, val); @@ -6249,6 +6258,9 @@ static int tg3_reset_hw(struct tg3 *tp) udelay(100); tp->rx_mode = RX_MODE_ENABLE; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) + tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE; + tw32_f(MAC_RX_MODE, tp->rx_mode); udelay(10); @@ -7907,7 +7919,8 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) return 0; } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) ethtool_op_set_tx_hw_csum(dev, data); else ethtool_op_set_tx_csum(dev, data); @@ -8332,7 +8345,8 @@ static int tg3_test_memory(struct tg3 *tp) int i; if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) mem_tbl = mem_tbl_5755; else mem_tbl = mem_tbl_5705; @@ -9310,6 +9324,7 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, nvram_cmd |= NVRAM_CMD_LAST; if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) && (tp->nvram_jedecnum == JEDEC_ST) && (nvram_cmd & NVRAM_CMD_FIRST)) { @@ -10044,6 +10059,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; @@ -10053,7 +10069,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) { tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; } else @@ -10063,6 +10080,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5705 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 && GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; @@ -10219,6 +10237,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) + tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; + /* Force the chip into D0. */ err = tg3_set_power_state(tp, PCI_D0); if (err) { @@ -10274,6 +10295,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG; if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && + (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) && (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787)) tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG; @@ -10413,7 +10435,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) /* All chips before 5787 can get confused if TX buffers * straddle the 4GB address boundary in some cases. */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) tp->dev->hard_start_xmit = tg3_start_xmit; else tp->dev->hard_start_xmit = tg3_start_xmit_dma_bug; @@ -11002,6 +11025,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5752: return "5752"; case PHY_ID_BCM5714: return "5714"; case PHY_ID_BCM5780: return "5780"; + case PHY_ID_BCM5755: return "5755"; case PHY_ID_BCM5787: return "5787"; case PHY_ID_BCM8002: return "8002/serdes"; case 0: return "serdes"; @@ -11350,7 +11374,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, * checksumming. */ if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) dev->features |= NETIF_F_HW_CSUM; else dev->features |= NETIF_F_IP_CSUM; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index baa34c4721d..672f375ef71 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -138,6 +138,7 @@ #define ASIC_REV_5752 0x06 #define ASIC_REV_5780 0x08 #define ASIC_REV_5714 0x09 +#define ASIC_REV_5755 0x0a #define ASIC_REV_5787 0x0b #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 @@ -456,6 +457,7 @@ #define RX_MODE_PROMISC 0x00000100 #define RX_MODE_NO_CRC_CHECK 0x00000200 #define RX_MODE_KEEP_VLAN_TAG 0x00000400 +#define RX_MODE_IPV6_CSUM_ENABLE 0x01000000 #define MAC_RX_STATUS 0x0000046c #define RX_STATUS_REMOTE_TX_XOFFED 0x00000001 #define RX_STATUS_XOFF_RCVD 0x00000002 @@ -1340,6 +1342,7 @@ #define GRC_LCLCTRL_CLEARINT 0x00000002 #define GRC_LCLCTRL_SETINT 0x00000004 #define GRC_LCLCTRL_INT_ON_ATTN 0x00000008 +#define GRC_LCLCTRL_GPIO_UART_SEL 0x00000010 /* 5755 only */ #define GRC_LCLCTRL_USE_SIG_DETECT 0x00000010 /* 5714/5780 only */ #define GRC_LCLCTRL_USE_EXT_SIG_DETECT 0x00000020 /* 5714/5780 only */ #define GRC_LCLCTRL_GPIO_INPUT3 0x00000020 @@ -2259,6 +2262,7 @@ struct tg3 { #define PHY_ID_BCM5752 0x60008100 #define PHY_ID_BCM5714 0x60008340 #define PHY_ID_BCM5780 0x60008350 +#define PHY_ID_BCM5755 0xbc050cc0 #define PHY_ID_BCM5787 0xbc050ce0 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_INVALID 0xffffffff @@ -2286,7 +2290,7 @@ struct tg3 { (X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \ (X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \ (X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \ - (X) == PHY_ID_BCM8002) + (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM8002) struct tg3_hw_stats *hw_stats; dma_addr_t stats_mapping; -- cgit v1.2.3 From d3c7b886978bef42f5ea487dec376c482d3cd7e3 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Thu, 23 Mar 2006 01:28:25 -0800 Subject: [TG3]: Add 5755 nvram support Add 5755 nvram support. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 43 +++++++++++++++++++++++++++++++++++++++++++ drivers/net/tg3.h | 3 +++ 2 files changed, 46 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index c69c8df088d..b4c5bab2bb4 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8938,6 +8938,47 @@ static void __devinit tg3_get_5752_nvram_info(struct tg3 *tp) } } +static void __devinit tg3_get_5755_nvram_info(struct tg3 *tp) +{ + u32 nvcfg1; + + nvcfg1 = tr32(NVRAM_CFG1); + + /* NVRAM protection for TPM */ + if (nvcfg1 & (1 << 27)) + tp->tg3_flags2 |= TG3_FLG2_PROTECTED_NVRAM; + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5755VENDOR_ATMEL_EEPROM_64KHZ: + case FLASH_5755VENDOR_ATMEL_EEPROM_376KHZ: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + break; + case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: + case FLASH_5755VENDOR_ATMEL_FLASH_1: + case FLASH_5755VENDOR_ATMEL_FLASH_2: + case FLASH_5755VENDOR_ATMEL_FLASH_3: + case FLASH_5755VENDOR_ATMEL_FLASH_4: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 264; + break; + case FLASH_5752VENDOR_ST_M45PE10: + case FLASH_5752VENDOR_ST_M45PE20: + case FLASH_5752VENDOR_ST_M45PE40: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + tp->nvram_pagesize = 256; + break; + } +} + static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp) { u32 nvcfg1; @@ -9011,6 +9052,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tg3_get_5752_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) + tg3_get_5755_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) tg3_get_5787_nvram_info(tp); else diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 672f375ef71..c43cc326420 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -1444,6 +1444,9 @@ #define FLASH_5755VENDOR_ATMEL_FLASH_1 0x03400001 #define FLASH_5755VENDOR_ATMEL_FLASH_2 0x03400002 #define FLASH_5755VENDOR_ATMEL_FLASH_3 0x03400000 +#define FLASH_5755VENDOR_ATMEL_FLASH_4 0x00000003 +#define FLASH_5755VENDOR_ATMEL_EEPROM_64KHZ 0x03c00003 +#define FLASH_5755VENDOR_ATMEL_EEPROM_376KHZ 0x03c00002 #define FLASH_5787VENDOR_ATMEL_EEPROM_64KHZ 0x03000003 #define FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ 0x03000002 #define FLASH_5787VENDOR_MICRO_EEPROM_64KHZ 0x03000000 -- cgit v1.2.3 From 95381c893dd71a534ab56f09b12a4e2118aa0f32 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Thu, 23 Mar 2006 01:29:06 -0800 Subject: [TG3]: Update driver version and reldate. Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b4c5bab2bb4..b5473325bff 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -69,8 +69,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.53" -#define DRV_MODULE_RELDATE "Mar 22, 2006" +#define DRV_MODULE_VERSION "3.54" +#define DRV_MODULE_RELDATE "Mar 23, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3 From 711e2c33ac9221a419a9e28d05dd78a6a9c5fd4d Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Wed, 22 Feb 2006 15:10:56 -0800 Subject: [PATCH] WE-20 for kernel 2.6.16 This is version 20 of the Wireless Extensions. This is the completion of the RtNetlink work I started early 2004, it enables the full Wireless Extension API over RtNetlink. Few comments on the patch : o totally driver transparent, no change in drivers needed. o iwevent were already RtNetlink based since they were created (around 2.5.7). This adds all the regular SET and GET requests over RtNetlink, using the exact same mechanism and data format as iwevents. o This is a Kconfig option, as currently most people have no need for it. Surprisingly, patch is actually small and well encapsulated. o Tested on SMP, attention as been paid to make it 64 bits clean. o Code do probably too many checks and could be further optimised, but better safe than sorry. o RtNetlink based version of the Wireless Tools available on my web page for people inclined to try out this stuff. I would also like to thank Alexey Kuznetsov for his helpful suggestions to make this patch better. Signed-off-by: Jean Tourrilhes Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 5b0a19a5058..6a1033ec06c 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -25,6 +25,15 @@ config NET_RADIO the tools from . +config NET_WIRELESS_RTNETLINK + bool "Wireless Extension API over RtNetlink" + ---help--- + Support the Wireless Extension API over the RtNetlink socket + in addition to the traditional ioctl interface (selected above). + + For now, few tools use this facility, but it might grow in the + future. The only downside is that it adds 4.5 kB to your kernel. + # Note : the cards are obsolete (can't buy them anymore), but the drivers # are not, as people are still using them... comment "Obsolete Wireless cards support (pre-802.11)" -- cgit v1.2.3 From 8ed965d612d9e9bc08805c75123f063cf6966311 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Thu, 23 Mar 2006 03:00:21 -0800 Subject: [PATCH] sem2mutex: drivers: raw, connector, dcdbas, ppp_generic Semaphore to mutex conversion. The conversion was generated via scripts, and the result was validated automatically via a script as well. Signed-off-by: Arjan van de Ven Signed-off-by: Ingo Molnar Cc: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/ppp_generic.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index f608c12e3e8..b2073fce821 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -198,11 +199,11 @@ static unsigned int cardmap_find_first_free(struct cardmap *map); static void cardmap_destroy(struct cardmap **map); /* - * all_ppp_sem protects the all_ppp_units mapping. + * all_ppp_mutex protects the all_ppp_units mapping. * It also ensures that finding a ppp unit in the all_ppp_units map * and updating its file.refcnt field is atomic. */ -static DECLARE_MUTEX(all_ppp_sem); +static DEFINE_MUTEX(all_ppp_mutex); static struct cardmap *all_ppp_units; static atomic_t ppp_unit_count = ATOMIC_INIT(0); @@ -804,7 +805,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, /* Attach to an existing ppp unit */ if (get_user(unit, p)) break; - down(&all_ppp_sem); + mutex_lock(&all_ppp_mutex); err = -ENXIO; ppp = ppp_find_unit(unit); if (ppp != 0) { @@ -812,7 +813,7 @@ static int ppp_unattached_ioctl(struct ppp_file *pf, struct file *file, file->private_data = &ppp->file; err = 0; } - up(&all_ppp_sem); + mutex_unlock(&all_ppp_mutex); break; case PPPIOCATTCHAN: @@ -2446,7 +2447,7 @@ ppp_create_interface(int unit, int *retp) dev->do_ioctl = ppp_net_ioctl; ret = -EEXIST; - down(&all_ppp_sem); + mutex_lock(&all_ppp_mutex); if (unit < 0) unit = cardmap_find_first_free(all_ppp_units); else if (cardmap_get(all_ppp_units, unit) != NULL) @@ -2465,12 +2466,12 @@ ppp_create_interface(int unit, int *retp) atomic_inc(&ppp_unit_count); cardmap_set(&all_ppp_units, unit, ppp); - up(&all_ppp_sem); + mutex_unlock(&all_ppp_mutex); *retp = 0; return ppp; out2: - up(&all_ppp_sem); + mutex_unlock(&all_ppp_mutex); free_netdev(dev); out1: kfree(ppp); @@ -2500,7 +2501,7 @@ static void ppp_shutdown_interface(struct ppp *ppp) { struct net_device *dev; - down(&all_ppp_sem); + mutex_lock(&all_ppp_mutex); ppp_lock(ppp); dev = ppp->dev; ppp->dev = NULL; @@ -2514,7 +2515,7 @@ static void ppp_shutdown_interface(struct ppp *ppp) ppp->file.dead = 1; ppp->owner = NULL; wake_up_interruptible(&ppp->file.rwait); - up(&all_ppp_sem); + mutex_unlock(&all_ppp_mutex); } /* @@ -2556,7 +2557,7 @@ static void ppp_destroy_interface(struct ppp *ppp) /* * Locate an existing ppp unit. - * The caller should have locked the all_ppp_sem. + * The caller should have locked the all_ppp_mutex. */ static struct ppp * ppp_find_unit(int unit) @@ -2601,7 +2602,7 @@ ppp_connect_channel(struct channel *pch, int unit) int ret = -ENXIO; int hdrlen; - down(&all_ppp_sem); + mutex_lock(&all_ppp_mutex); ppp = ppp_find_unit(unit); if (ppp == 0) goto out; @@ -2626,7 +2627,7 @@ ppp_connect_channel(struct channel *pch, int unit) outl: write_unlock_bh(&pch->upl); out: - up(&all_ppp_sem); + mutex_unlock(&all_ppp_mutex); return ret; } -- cgit v1.2.3 From 394e3902c55e667945f6f1c2bdbc59842cce70f7 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 23 Mar 2006 03:01:05 -0800 Subject: [PATCH] more for_each_cpu() conversions When we stop allocating percpu memory for not-possible CPUs we must not touch the percpu data for not-possible CPUs at all. The correct way of doing this is to test cpu_possible() or to use for_each_cpu(). This patch is a kernel-wide sweep of all instances of NR_CPUS. I found very few instances of this bug, if any. But the patch converts lots of open-coded test to use the preferred helper macros. Cc: Mikael Starvik Cc: David Howells Acked-by: Kyle McMartin Cc: Anton Blanchard Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Martin Schwidefsky Cc: Heiko Carstens Cc: Paul Mundt Cc: "David S. Miller" Cc: William Lee Irwin III Cc: Andi Kleen Cc: Christian Zankel Cc: Philippe Elie Cc: Nathan Scott Cc: Jens Axboe Cc: Eric Dumazet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/loopback.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 690a1aae0b3..0c13795dca3 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -172,11 +172,9 @@ static struct net_device_stats *get_stats(struct net_device *dev) memset(stats, 0, sizeof(struct net_device_stats)); - for (i=0; i < NR_CPUS; i++) { + for_each_cpu(i) { struct net_device_stats *lb_stats; - if (!cpu_possible(i)) - continue; lb_stats = &per_cpu(loopback_stats, i); stats->rx_bytes += lb_stats->rx_bytes; stats->tx_bytes += lb_stats->tx_bytes; -- cgit v1.2.3 From 934d8bf142541ea013bc4002e200fa0e6815bf38 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 16 Mar 2006 13:46:23 -0500 Subject: [PATCH] wireless/airo: clean up printk usage to print device name Show the specific device that driver messages are about. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 191 ++++++++++++++++++++++++-------------------- 1 file changed, 105 insertions(+), 86 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 864937a409e..8a0abb668ed 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -1216,6 +1216,22 @@ static int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime); static int flashputbuf(struct airo_info *ai); static int flashrestart(struct airo_info *ai,struct net_device *dev); +#define airo_print(type, name, fmt, args...) \ + { printk(type "airo(%s): " fmt "\n", name, ##args); } + +#define airo_print_info(name, fmt, args...) \ + airo_print(KERN_INFO, name, fmt, ##args) + +#define airo_print_dbg(name, fmt, args...) \ + airo_print(KERN_DEBUG, name, fmt, ##args) + +#define airo_print_warn(name, fmt, args...) \ + airo_print(KERN_WARNING, name, fmt, ##args) + +#define airo_print_err(name, fmt, args...) \ + airo_print(KERN_ERR, name, fmt, ##args) + + /*********************************************************************** * MIC ROUTINES * *********************************************************************** @@ -1294,7 +1310,7 @@ static int micsetup(struct airo_info *ai) { ai->tfm = crypto_alloc_tfm("aes", CRYPTO_TFM_REQ_MAY_SLEEP); if (ai->tfm == NULL) { - printk(KERN_ERR "airo: failed to load transform for AES\n"); + airo_print_err(ai->dev->name, "failed to load transform for AES"); return ERROR; } @@ -1726,11 +1742,11 @@ static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm, int lo wkr.kindex = cpu_to_le16(wkr.kindex); wkr.klen = cpu_to_le16(wkr.klen); rc = PC4500_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr), lock); - if (rc!=SUCCESS) printk(KERN_ERR "airo: WEP_TEMP set %x\n", rc); + if (rc!=SUCCESS) airo_print_err(ai->dev->name, "WEP_TEMP set %x", rc); if (perm) { rc = PC4500_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr), lock); if (rc!=SUCCESS) { - printk(KERN_ERR "airo: WEP_PERM set %x\n", rc); + airo_print_err(ai->dev->name, "WEP_PERM set %x", rc); } } return rc; @@ -1909,7 +1925,7 @@ static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct airo_info *ai = dev->priv; if (!skb) { - printk(KERN_ERR "airo: %s: skb==NULL\n",__FUNCTION__); + airo_print_err(dev->name, "%s: skb == NULL!",__FUNCTION__); return 0; } npacks = skb_queue_len (&ai->txq); @@ -1955,8 +1971,8 @@ static int mpi_send_packet (struct net_device *dev) /* get a packet to send */ if ((skb = skb_dequeue(&ai->txq)) == 0) { - printk (KERN_ERR - "airo: %s: Dequeue'd zero in send_packet()\n", + airo_print_err(dev->name, + "%s: Dequeue'd zero in send_packet()", __FUNCTION__); return 0; } @@ -2108,7 +2124,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { u32 *fids = priv->fids; if ( skb == NULL ) { - printk( KERN_ERR "airo: skb == NULL!!!\n" ); + airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__); return 0; } @@ -2179,7 +2195,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { } if ( skb == NULL ) { - printk( KERN_ERR "airo: skb == NULL!!!\n" ); + airo_print_err(dev->name, "%s: skb == NULL!", __FUNCTION__); return 0; } @@ -2434,7 +2450,7 @@ static int mpi_init_descriptors (struct airo_info *ai) cmd.parm2 = MPI_MAX_FIDS; rc=issuecommand(ai, &cmd, &rsp); if (rc != SUCCESS) { - printk(KERN_ERR "airo: Couldn't allocate RX FID\n"); + airo_print_err(ai->dev->name, "Couldn't allocate RX FID"); return rc; } @@ -2462,7 +2478,7 @@ static int mpi_init_descriptors (struct airo_info *ai) rc=issuecommand(ai, &cmd, &rsp); if (rc != SUCCESS) { - printk(KERN_ERR "airo: Couldn't allocate TX FID\n"); + airo_print_err(ai->dev->name, "Couldn't allocate TX FID"); return rc; } @@ -2476,7 +2492,7 @@ static int mpi_init_descriptors (struct airo_info *ai) cmd.parm2 = 1; /* Magic number... */ rc=issuecommand(ai, &cmd, &rsp); if (rc != SUCCESS) { - printk(KERN_ERR "airo: Couldn't allocate RID\n"); + airo_print_err(ai->dev->name, "Couldn't allocate RID"); return rc; } @@ -2508,25 +2524,25 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, aux_len = AUXMEMSIZE; if (!request_mem_region(mem_start, mem_len, name)) { - printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n", + airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s", (int)mem_start, (int)mem_len, name); goto out; } if (!request_mem_region(aux_start, aux_len, name)) { - printk(KERN_ERR "airo: Couldn't get region %x[%x] for %s\n", + airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s", (int)aux_start, (int)aux_len, name); goto free_region1; } ai->pcimem = ioremap(mem_start, mem_len); if (!ai->pcimem) { - printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n", + airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s", (int)mem_start, (int)mem_len, name); goto free_region2; } ai->pciaux = ioremap(aux_start, aux_len); if (!ai->pciaux) { - printk(KERN_ERR "airo: Couldn't map region %x[%x] for %s\n", + airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s", (int)aux_start, (int)aux_len, name); goto free_memmap; } @@ -2534,7 +2550,7 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci, /* Reserve PKTSIZE for each fid and 2K for the Rids */ ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma); if (!ai->shared) { - printk(KERN_ERR "airo: Couldn't alloc_consistent %d\n", + airo_print_err(ai->dev->name, "Couldn't alloc_consistent %d", PCI_SHARED_LEN); goto free_auxmap; } @@ -2681,22 +2697,22 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, /* Create the network device object. */ dev = alloc_etherdev(sizeof(*ai)); if (!dev) { - printk(KERN_ERR "airo: Couldn't alloc_etherdev\n"); + airo_print_err("", "Couldn't alloc_etherdev"); return NULL; } if (dev_alloc_name(dev, dev->name) < 0) { - printk(KERN_ERR "airo: Couldn't get name!\n"); + airo_print_err("", "Couldn't get name!"); goto err_out_free; } ai = dev->priv; ai->wifidev = NULL; ai->flags = 0; + ai->dev = dev; if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) { - printk(KERN_DEBUG "airo: Found an MPI350 card\n"); + airo_print_dbg(dev->name, "Found an MPI350 card"); set_bit(FLAG_MPI, &ai->flags); } - ai->dev = dev; spin_lock_init(&ai->aux_lock); sema_init(&ai->sem, 1); ai->config.len = 0; @@ -2738,27 +2754,28 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev ); if (rc) { - printk(KERN_ERR "airo: register interrupt %d failed, rc %d\n", irq, rc ); + airo_print_err(dev->name, "register interrupt %d failed, rc %d", + irq, rc); goto err_out_unlink; } if (!is_pcmcia) { if (!request_region( dev->base_addr, 64, dev->name )) { rc = -EBUSY; - printk(KERN_ERR "airo: Couldn't request region\n"); + airo_print_err(dev->name, "Couldn't request region"); goto err_out_irq; } } if (test_bit(FLAG_MPI,&ai->flags)) { if (mpi_map_card(ai, pci, dev->name)) { - printk(KERN_ERR "airo: Could not map memory\n"); + airo_print_err(dev->name, "Could not map memory"); goto err_out_res; } } if (probe) { if ( setup_card( ai, dev->dev_addr, 1 ) != SUCCESS ) { - printk( KERN_ERR "airo: MAC could not be enabled\n" ); + airo_print_err(dev->name, "MAC could not be enabled" ); rc = -EIO; goto err_out_map; } @@ -2769,14 +2786,13 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, rc = register_netdev(dev); if (rc) { - printk(KERN_ERR "airo: Couldn't register_netdev\n"); + airo_print_err(dev->name, "Couldn't register_netdev"); goto err_out_map; } ai->wifidev = init_wifidev(ai, dev); set_bit(FLAG_REGISTERED,&ai->flags); - printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", - dev->name, + airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x", dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); @@ -2840,10 +2856,10 @@ int reset_airo_card( struct net_device *dev ) return -1; if ( setup_card(ai, dev->dev_addr, 1 ) != SUCCESS ) { - printk( KERN_ERR "airo: MAC could not be enabled\n" ); + airo_print_err(dev->name, "MAC could not be enabled"); return -1; } - printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n", dev->name, + airo_print_info(dev->name, "MAC enabled %x:%x:%x:%x:%x:%x", dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); /* Allocate the transmit buffers if needed */ @@ -3118,7 +3134,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) len = le16_to_cpu(hdr.len); if (len > 2312) { - printk( KERN_ERR "airo: Bad size %d\n", len ); + airo_print_err(apriv->dev->name, "Bad size %d", len); goto badrx; } if (len == 0) @@ -3161,10 +3177,12 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) bap_read (apriv, &gap, sizeof(gap), BAP0); gap = le16_to_cpu(gap); if (gap) { - if (gap <= 8) + if (gap <= 8) { bap_read (apriv, tmpbuf, gap, BAP0); - else - printk(KERN_ERR "airo: gaplen too big. Problems will follow...\n"); + } else { + airo_print_err(apriv->dev->name, "gaplen too " + "big. Problems will follow..."); + } } bap_read (apriv, buffer + hdrlen/2, len, BAP0); } else { @@ -3281,12 +3299,13 @@ exitrx: } } else { OUT4500( apriv, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); - printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" ); + airo_print_err(apriv->dev->name, "Unallocated FID was " + "used to xmit" ); } } exittx: if ( status & ~STATUS_INTS & ~IGNORE_INTS ) - printk( KERN_WARNING "airo: Got weird status %x\n", + airo_print_warn(apriv->dev->name, "Got weird status %x", status & ~STATUS_INTS & ~IGNORE_INTS ); } @@ -3359,8 +3378,8 @@ static int enable_MAC( struct airo_info *ai, Resp *rsp, int lock ) { up(&ai->sem); if (rc) - printk(KERN_ERR "%s: Cannot enable MAC, err=%d\n", - __FUNCTION__,rc); + airo_print_err(ai->dev->name, "%s: Cannot enable MAC, err=%d", + __FUNCTION__, rc); return rc; } @@ -3490,7 +3509,7 @@ void mpi_receive_802_11 (struct airo_info *ai) hdr.len = 0; len = le16_to_cpu(hdr.len); if (len > 2312) { - printk( KERN_ERR "airo: Bad size %d\n", len ); + airo_print_err(ai->dev->name, "Bad size %d", len); goto badrx; } if (len == 0) @@ -3531,8 +3550,8 @@ void mpi_receive_802_11 (struct airo_info *ai) if (gap <= 8) ptr += gap; else - printk(KERN_ERR - "airo: gaplen too big. Problems will follow...\n"); + airo_print_err(ai->dev->name, + "gaplen too big. Problems will follow..."); } memcpy ((char *)buffer + hdrlen, ptr, len); ptr += len; @@ -3604,15 +3623,15 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) if (issuecommand(ai, &cmd, &rsp) != SUCCESS) { if (lock) up(&ai->sem); - printk(KERN_ERR "airo: Error checking for AUX port\n"); + airo_print_err(ai->dev->name, "Error checking for AUX port"); return ERROR; } if (!aux_bap || rsp.status & 0xff00) { ai->bap_read = fast_bap_read; - printk(KERN_DEBUG "airo: Doing fast bap_reads\n"); + airo_print_dbg(ai->dev->name, "Doing fast bap_reads"); } else { ai->bap_read = aux_bap_read; - printk(KERN_DEBUG "airo: Doing AUX bap_reads\n"); + airo_print_dbg(ai->dev->name, "Doing AUX bap_reads"); } } if (lock) @@ -3643,7 +3662,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) if (cap_rid.softCap & 8) ai->config.rmode |= RXMODE_NORMALIZED_RSSI; else - printk(KERN_WARNING "airo: unknown received signal level scale\n"); + airo_print_warn(ai->dev->name, "unknown received signal " + "level scale"); } ai->config.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS; ai->config.authType = AUTH_OPEN; @@ -3706,7 +3726,8 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock) status = enable_MAC(ai, &rsp, lock); if ( status != SUCCESS || (rsp.status & 0xFF00) != 0) { - printk( KERN_ERR "airo: Bad MAC enable reason = %x, rid = %x, offset = %d\n", rsp.rsp0, rsp.rsp1, rsp.rsp2 ); + airo_print_err(ai->dev->name, "Bad MAC enable reason = %x, rid = %x," + " offset = %d", rsp.rsp0, rsp.rsp1, rsp.rsp2 ); return ERROR; } @@ -3749,8 +3770,8 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { } if ( max_tries == -1 ) { - printk( KERN_ERR - "airo: Max tries exceeded when issueing command\n" ); + airo_print_err(ai->dev->name, + "Max tries exceeded when issueing command"); if (IN4500(ai, COMMAND) & COMMAND_BUSY) OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY); return ERROR; @@ -3762,11 +3783,11 @@ static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) { pRsp->rsp1 = IN4500(ai, RESP1); pRsp->rsp2 = IN4500(ai, RESP2); if ((pRsp->status & 0xff00)!=0 && pCmd->cmd != CMD_SOFTRESET) { - printk (KERN_ERR "airo: cmd= %x\n", pCmd->cmd); - printk (KERN_ERR "airo: status= %x\n", pRsp->status); - printk (KERN_ERR "airo: Rsp0= %x\n", pRsp->rsp0); - printk (KERN_ERR "airo: Rsp1= %x\n", pRsp->rsp1); - printk (KERN_ERR "airo: Rsp2= %x\n", pRsp->rsp2); + airo_print_err(ai->dev->name, "cmd= %x\n", pCmd->cmd); + airo_print_err(ai->dev->name, "status= %x\n", pRsp->status); + airo_print_err(ai->dev->name, "Rsp0= %x\n", pRsp->rsp0); + airo_print_err(ai->dev->name, "Rsp1= %x\n", pRsp->rsp1); + airo_print_err(ai->dev->name, "Rsp2= %x\n", pRsp->rsp2); } // clear stuck command busy if necessary @@ -3799,15 +3820,15 @@ static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap ) } } else if ( status & BAP_ERR ) { /* invalid rid or offset */ - printk( KERN_ERR "airo: BAP error %x %d\n", + airo_print_err(ai->dev->name, "BAP error %x %d", status, whichbap ); return ERROR; } else if (status & BAP_DONE) { // success return SUCCESS; } if ( !(max_tries--) ) { - printk( KERN_ERR - "airo: BAP setup error too many retries\n" ); + airo_print_err(ai->dev->name, + "airo: BAP setup error too many retries\n"); return ERROR; } // -- PC4500 missed it, try again @@ -3962,8 +3983,8 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len, in len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2; if ( len <= 2 ) { - printk( KERN_ERR - "airo: Rid %x has a length of %d which is too short\n", + airo_print_err(ai->dev->name, + "Rid %x has a length of %d which is too short", (int)rid, (int)len ); rc = ERROR; goto done; @@ -3996,8 +4017,8 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, Resp rsp; if (test_bit(FLAG_ENABLED, &ai->flags) && (RID_WEP_TEMP != rid)) - printk(KERN_ERR - "%s: MAC should be disabled (rid=%04x)\n", + airo_print_err(ai->dev->name, + "%s: MAC should be disabled (rid=%04x)", __FUNCTION__, rid); memset(&cmd, 0, sizeof(cmd)); memset(&rsp, 0, sizeof(rsp)); @@ -4013,7 +4034,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, &ai->config_desc.rid_desc, sizeof(Rid)); if (len < 4 || len > 2047) { - printk(KERN_ERR "%s: len=%d\n",__FUNCTION__,len); + airo_print_err(ai->dev->name, "%s: len=%d", __FUNCTION__, len); rc = -1; } else { memcpy((char *)ai->config_desc.virtual_host_addr, @@ -4021,10 +4042,10 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid, rc = issuecommand(ai, &cmd, &rsp); if ((rc & 0xff00) != 0) { - printk(KERN_ERR "%s: Write rid Error %d\n", - __FUNCTION__,rc); - printk(KERN_ERR "%s: Cmd=%04x\n", - __FUNCTION__,cmd.cmd); + airo_print_err(ai->dev->name, "%s: Write rid Error %d", + __FUNCTION__, rc); + airo_print_err(ai->dev->name, "%s: Cmd=%04x", + __FUNCTION__, cmd.cmd); } if ((rsp.status & 0x7f00)) @@ -4123,7 +4144,7 @@ static int transmit_802_3_packet(struct airo_info *ai, int len, char *pPacket) len >>= 16; if (len <= ETH_ALEN * 2) { - printk( KERN_WARNING "Short packet %d\n", len ); + airo_print_warn(ai->dev->name, "Short packet %d", len); return ERROR; } len -= ETH_ALEN * 2; @@ -4187,7 +4208,7 @@ static int transmit_802_11_packet(struct airo_info *ai, int len, char *pPacket) } if (len < hdrlen) { - printk( KERN_WARNING "Short packet %d\n", len ); + airo_print_warn(ai->dev->name, "Short packet %d", len); return ERROR; } @@ -4584,15 +4605,14 @@ static int proc_stats_rid_open( struct inode *inode, i*44096) { - printk(KERN_WARNING - "airo: Potentially disasterous buffer overflow averted!\n"); + airo_print_warn(apriv->dev->name, + "Potentially disasterous buffer overflow averted!"); break; } j+=sprintf(data->rbuffer+j, "%s: %u\n", statsLabels[i], vals[i]); } if (i*4>=stats.len){ - printk(KERN_WARNING - "airo: Got a short rid\n"); + airo_print_warn(apriv->dev->name, "Got a short rid"); } data->readlen = j; return 0; @@ -4798,8 +4818,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { case 'd': ai->config.modulation=MOD_DEFAULT; set_bit(FLAG_COMMIT, &ai->flags); break; case 'c': ai->config.modulation=MOD_CCK; set_bit(FLAG_COMMIT, &ai->flags); break; case 'm': ai->config.modulation=MOD_MOK; set_bit(FLAG_COMMIT, &ai->flags); break; - default: - printk( KERN_WARNING "airo: Unknown modulation\n" ); + default: airo_print_warn(ai->dev->name, "Unknown modulation"); } } else if (!strncmp(line, "Preamble: ", 10)) { line += 10; @@ -4807,10 +4826,10 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { case 'a': ai->config.preamble=PREAMBLE_AUTO; set_bit(FLAG_COMMIT, &ai->flags); break; case 'l': ai->config.preamble=PREAMBLE_LONG; set_bit(FLAG_COMMIT, &ai->flags); break; case 's': ai->config.preamble=PREAMBLE_SHORT; set_bit(FLAG_COMMIT, &ai->flags); break; - default: printk(KERN_WARNING "airo: Unknown preamble\n"); + default: airo_print_warn(ai->dev->name, "Unknown preamble"); } } else { - printk( KERN_WARNING "Couldn't figure out %s\n", line ); + airo_print_warn(ai->dev->name, "Couldn't figure out %s", line); } while( line[0] && line[0] != '\n' ) line++; if ( line[0] ) line++; @@ -5076,7 +5095,7 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) { } j = 2; } else { - printk(KERN_ERR "airo: WepKey passed invalid key index\n"); + airo_print_err(ai->dev->name, "WepKey passed invalid key index"); return; } @@ -5489,17 +5508,16 @@ static int __init airo_init_module( void ) airo_entry->gid = proc_gid; for( i = 0; i < 4 && io[i] && irq[i]; i++ ) { - printk( KERN_INFO - "airo: Trying to configure ISA adapter at irq=%d io=0x%x\n", - irq[i], io[i] ); + airo_print_info("", "Trying to configure ISA adapter at irq=%d " + "io=0x%x", irq[i], io[i] ); if (init_airo_card( irq[i], io[i], 0, NULL )) have_isa_dev = 1; } #ifdef CONFIG_PCI - printk( KERN_INFO "airo: Probing for PCI adapters\n" ); + airo_print_info("", "Probing for PCI adapters"); pci_register_driver(&airo_driver); - printk( KERN_INFO "airo: Finished probing for PCI adapters\n" ); + airo_print_info("", "Finished probing for PCI adapters"); #endif /* Always exit with success, as we are a library module @@ -5511,7 +5529,7 @@ static int __init airo_init_module( void ) static void __exit airo_cleanup_module( void ) { while( airo_devices ) { - printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name ); + airo_print_info(airo_devices->dev->name, "Unregistering...\n"); stop_airo_card( airo_devices->dev, 1 ); } #ifdef CONFIG_PCI @@ -5622,7 +5640,8 @@ static int airo_set_freq(struct net_device *dev, /* We should do a better check than that, * based on the card capability !!! */ if((channel < 1) || (channel > 14)) { - printk(KERN_DEBUG "%s: New channel value of %d is invalid!\n", dev->name, fwrq->m); + airo_print_dbg(dev->name, "New channel value of %d is invalid!", + fwrq->m); rc = -EINVAL; } else { readConfigRid(local, 1); @@ -7711,7 +7730,7 @@ static int cmdreset(struct airo_info *ai) { disable_MAC(ai, 1); if(!waitbusy (ai)){ - printk(KERN_INFO "Waitbusy hang before RESET\n"); + airo_print_info(ai->dev->name, "Waitbusy hang before RESET"); return -EBUSY; } @@ -7720,7 +7739,7 @@ static int cmdreset(struct airo_info *ai) { ssleep(1); /* WAS 600 12/7/00 */ if(!waitbusy (ai)){ - printk(KERN_INFO "Waitbusy hang AFTER RESET\n"); + airo_print_info(ai->dev->name, "Waitbusy hang AFTER RESET"); return -EBUSY; } return 0; @@ -7748,7 +7767,7 @@ static int setflashmode (struct airo_info *ai) { if(!waitbusy(ai)) { clear_bit (FLAG_FLASHING, &ai->flags); - printk(KERN_INFO "Waitbusy hang after setflash mode\n"); + airo_print_info(ai->dev->name, "Waitbusy hang after setflash mode"); return -EIO; } return 0; @@ -7777,7 +7796,7 @@ static int flashpchar(struct airo_info *ai,int byte,int dwelltime) { /* timeout for busy clear wait */ if(waittime <= 0 ){ - printk(KERN_INFO "flash putchar busywait timeout! \n"); + airo_print_info(ai->dev->name, "flash putchar busywait timeout!"); return -EBUSY; } -- cgit v1.2.3 From 15db2763202b9479f3d30ea61a283be4fc48559d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 16 Mar 2006 13:46:27 -0500 Subject: [PATCH] wireless/airo: define default MTU The number 2312 was used all over the place to refer to the card's default MTU. Make it a #define and use that everywhere rather than the number. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 8a0abb668ed..6f591abacfd 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -902,6 +902,7 @@ static char swversion[] = "2.1"; #define NUM_MODULES 2 #define MIC_MSGLEN_MAX 2400 #define EMMH32_MSGLEN_MAX MIC_MSGLEN_MAX +#define AIRO_DEF_MTU 2312 typedef struct { u32 size; // size @@ -2642,7 +2643,7 @@ static void wifi_setup(struct net_device *dev) dev->type = ARPHRD_IEEE80211; dev->hard_header_len = ETH_HLEN; - dev->mtu = 2312; + dev->mtu = AIRO_DEF_MTU; dev->addr_len = ETH_ALEN; dev->tx_queue_len = 100; @@ -2799,7 +2800,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, /* Allocate the transmit buffers */ if (probe && !test_bit(FLAG_MPI,&ai->flags)) for( i = 0; i < MAX_FIDS; i++ ) - ai->fids[i] = transmit_allocate(ai,2312,i>=MAX_FIDS/2); + ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2); setup_proc_entry( dev, dev->priv ); /* XXX check for failure */ netif_start_queue(dev); @@ -2865,7 +2866,7 @@ int reset_airo_card( struct net_device *dev ) /* Allocate the transmit buffers if needed */ if (!test_bit(FLAG_MPI,&ai->flags)) for( i = 0; i < MAX_FIDS; i++ ) - ai->fids[i] = transmit_allocate (ai,2312,i>=MAX_FIDS/2); + ai->fids[i] = transmit_allocate (ai,AIRO_DEF_MTU,i>=MAX_FIDS/2); enable_interrupts( ai ); netif_wake_queue(dev); @@ -3133,7 +3134,7 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) } len = le16_to_cpu(hdr.len); - if (len > 2312) { + if (len > AIRO_DEF_MTU) { airo_print_err(apriv->dev->name, "Bad size %d", len); goto badrx; } @@ -3508,7 +3509,7 @@ void mpi_receive_802_11 (struct airo_info *ai) if (ai->wifidev == NULL) hdr.len = 0; len = le16_to_cpu(hdr.len); - if (len > 2312) { + if (len > AIRO_DEF_MTU) { airo_print_err(ai->dev->name, "Bad size %d", len); goto badrx; } @@ -4774,7 +4775,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { line += 14; v = get_dec_u16(line, &i, 4); - v = (v<0) ? 0 : ((v>2312) ? 2312 : v); + v = (v<0) ? 0 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); ai->config.rtsThres = (u16)v; set_bit (FLAG_COMMIT, &ai->flags); } else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) { @@ -4808,7 +4809,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) { line += 15; v = get_dec_u16(line, &i, 4); - v = (v<256) ? 256 : ((v>2312) ? 2312 : v); + v = (v<256) ? 256 : ((v>AIRO_DEF_MTU) ? AIRO_DEF_MTU : v); v = v & 0xfffe; /* Make sure its even */ ai->config.fragThresh = (u16)v; set_bit (FLAG_COMMIT, &ai->flags); @@ -5965,8 +5966,8 @@ static int airo_set_rts(struct net_device *dev, int rthr = vwrq->value; if(vwrq->disabled) - rthr = 2312; - if((rthr < 0) || (rthr > 2312)) { + rthr = AIRO_DEF_MTU; + if((rthr < 0) || (rthr > AIRO_DEF_MTU)) { return -EINVAL; } readConfigRid(local, 1); @@ -5989,7 +5990,7 @@ static int airo_get_rts(struct net_device *dev, readConfigRid(local, 1); vwrq->value = local->config.rtsThres; - vwrq->disabled = (vwrq->value >= 2312); + vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU); vwrq->fixed = 1; return 0; @@ -6008,8 +6009,8 @@ static int airo_set_frag(struct net_device *dev, int fthr = vwrq->value; if(vwrq->disabled) - fthr = 2312; - if((fthr < 256) || (fthr > 2312)) { + fthr = AIRO_DEF_MTU; + if((fthr < 256) || (fthr > AIRO_DEF_MTU)) { return -EINVAL; } fthr &= ~0x1; /* Get an even value - is it really needed ??? */ @@ -6033,7 +6034,7 @@ static int airo_get_frag(struct net_device *dev, readConfigRid(local, 1); vwrq->value = local->config.fragThresh; - vwrq->disabled = (vwrq->value >= 2312); + vwrq->disabled = (vwrq->value >= AIRO_DEF_MTU); vwrq->fixed = 1; return 0; @@ -6728,9 +6729,9 @@ static int airo_get_range(struct net_device *dev, range->throughput = 1500 * 1000; range->min_rts = 0; - range->max_rts = 2312; + range->max_rts = AIRO_DEF_MTU; range->min_frag = 256; - range->max_frag = 2312; + range->max_frag = AIRO_DEF_MTU; if(cap_rid.softCap & 2) { // WEP: RC4 40 bits @@ -7885,7 +7886,7 @@ static int flashrestart(struct airo_info *ai,struct net_device *dev){ if (!test_bit(FLAG_MPI,&ai->flags)) for( i = 0; i < MAX_FIDS; i++ ) { ai->fids[i] = transmit_allocate - ( ai, 2312, i >= MAX_FIDS / 2 ); + ( ai, AIRO_DEF_MTU, i >= MAX_FIDS / 2 ); } ssleep(1); /* Added 12/7/00 */ -- cgit v1.2.3 From 9e75af30d529d54fc650586776c100d0665c0c93 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 16 Mar 2006 13:46:29 -0500 Subject: [PATCH] wireless/airo: cache wireless scans Observed problems when multiple processes request scans and subsequently scan results. This causes a scan result request to hit card registers before the scan is complete, returning an incomplete scan list and possibly making the card very angry. Instead, cache the results of a wireless scan and serve result requests from the cache, rather than hitting the hardware for them. Signed-off-by: Dan Williams Signed-off-by: John W. Linville --- drivers/net/wireless/airo.c | 231 +++++++++++++++++++++++++++++++++----------- 1 file changed, 172 insertions(+), 59 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 6f591abacfd..108d9fed8f0 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -769,6 +769,11 @@ typedef struct { u16 atimWindow; } BSSListRid; +typedef struct { + BSSListRid bss; + struct list_head list; +} BSSListElement; + typedef struct { u8 rssipct; u8 rssidBm; @@ -1120,6 +1125,8 @@ static int decapsulate(struct airo_info *ai, MICBuffer *mic, etherHead *pPacket, static u8 airo_rssi_to_dbm (tdsRssiEntry *rssi_rid, u8 rssi); static u8 airo_dbm_to_pct (tdsRssiEntry *rssi_rid, u8 dbm); +static void airo_networks_free(struct airo_info *ai); + struct airo_info { struct net_device_stats stats; struct net_device *dev; @@ -1151,7 +1158,7 @@ struct airo_info { #define FLAG_COMMIT 13 #define FLAG_RESET 14 #define FLAG_FLASHING 15 -#define JOB_MASK 0x1ff0000 +#define JOB_MASK 0x2ff0000 #define JOB_DIE 16 #define JOB_XMIT 17 #define JOB_XMIT11 18 @@ -1161,6 +1168,7 @@ struct airo_info { #define JOB_EVENT 22 #define JOB_AUTOWEP 23 #define JOB_WSTATS 24 +#define JOB_SCAN_RESULTS 25 int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen, int whichbap); unsigned short *flash; @@ -1177,7 +1185,7 @@ struct airo_info { } xmit, xmit11; struct net_device *wifidev; struct iw_statistics wstats; // wireless stats - unsigned long scan_timestamp; /* Time started to scan */ + unsigned long scan_timeout; /* Time scan should be read */ struct iw_spy_data spy_data; struct iw_public_data wireless_data; /* MIC stuff */ @@ -1199,6 +1207,10 @@ struct airo_info { APListRid *APList; #define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE char proc_name[IFNAMSIZ]; + + struct list_head network_list; + struct list_head network_free_list; + BSSListElement *networks; }; static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, @@ -2381,6 +2393,8 @@ void stop_airo_card( struct net_device *dev, int freeres ) dev_kfree_skb(skb); } + airo_networks_free (ai); + kfree(ai->flash); kfree(ai->rssi); kfree(ai->APList); @@ -2687,6 +2701,42 @@ static int reset_card( struct net_device *dev , int lock) { return 0; } +#define MAX_NETWORK_COUNT 64 +static int airo_networks_allocate(struct airo_info *ai) +{ + if (ai->networks) + return 0; + + ai->networks = + kzalloc(MAX_NETWORK_COUNT * sizeof(BSSListElement), + GFP_KERNEL); + if (!ai->networks) { + airo_print_warn(ai->dev->name, "Out of memory allocating beacons"); + return -ENOMEM; + } + + return 0; +} + +static void airo_networks_free(struct airo_info *ai) +{ + if (!ai->networks) + return; + kfree(ai->networks); + ai->networks = NULL; +} + +static void airo_networks_initialize(struct airo_info *ai) +{ + int i; + + INIT_LIST_HEAD(&ai->network_free_list); + INIT_LIST_HEAD(&ai->network_list); + for (i = 0; i < MAX_NETWORK_COUNT; i++) + list_add_tail(&ai->networks[i].list, + &ai->network_free_list); +} + static struct net_device *_init_airo_card( unsigned short irq, int port, int is_pcmcia, struct pci_dev *pci, struct device *dmdev ) @@ -2728,6 +2778,10 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, if (rc) goto err_out_thr; + if (airo_networks_allocate (ai)) + goto err_out_unlink; + airo_networks_initialize (ai); + /* The Airo-specific entries in the device structure. */ if (test_bit(FLAG_MPI,&ai->flags)) { skb_queue_head_init (&ai->txq); @@ -2749,7 +2803,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, SET_NETDEV_DEV(dev, dmdev); - reset_card (dev, 1); msleep(400); @@ -2892,6 +2945,65 @@ static void airo_send_event(struct net_device *dev) { wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); } +static void airo_process_scan_results (struct airo_info *ai) { + union iwreq_data wrqu; + BSSListRid BSSList; + int rc; + BSSListElement * loop_net; + BSSListElement * tmp_net; + + /* Blow away current list of scan results */ + list_for_each_entry_safe (loop_net, tmp_net, &ai->network_list, list) { + list_move_tail (&loop_net->list, &ai->network_free_list); + /* Don't blow away ->list, just BSS data */ + memset (loop_net, 0, sizeof (loop_net->bss)); + } + + /* Try to read the first entry of the scan result */ + rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 0); + if((rc) || (BSSList.index == 0xffff)) { + /* No scan results */ + goto out; + } + + /* Read and parse all entries */ + tmp_net = NULL; + while((!rc) && (BSSList.index != 0xffff)) { + /* Grab a network off the free list */ + if (!list_empty(&ai->network_free_list)) { + tmp_net = list_entry(ai->network_free_list.next, + BSSListElement, list); + list_del(ai->network_free_list.next); + } + + if (tmp_net != NULL) { + memcpy(tmp_net, &BSSList, sizeof(tmp_net->bss)); + list_add_tail(&tmp_net->list, &ai->network_list); + tmp_net = NULL; + } + + /* Read next entry */ + rc = PC4500_readrid(ai, RID_BSSLISTNEXT, + &BSSList, sizeof(BSSList), 0); + } + +out: + ai->scan_timeout = 0; + clear_bit(JOB_SCAN_RESULTS, &ai->flags); + up(&ai->sem); + + /* Send an empty event to user space. + * We don't send the received data on + * the event because it would require + * us to do complex transcoding, and + * we want to minimise the work done in + * the irq handler. Use a request to + * extract the data - Jean II */ + wrqu.data.length = 0; + wrqu.data.flags = 0; + wireless_send_event(ai->dev, SIOCGIWSCAN, &wrqu, NULL); +} + static int airo_thread(void *data) { struct net_device *dev = data; struct airo_info *ai = dev->priv; @@ -2921,13 +3033,26 @@ static int airo_thread(void *data) { set_current_state(TASK_INTERRUPTIBLE); if (ai->flags & JOB_MASK) break; - if (ai->expires) { - if (time_after_eq(jiffies,ai->expires)){ + if (ai->expires || ai->scan_timeout) { + if (ai->scan_timeout && + time_after_eq(jiffies,ai->scan_timeout)){ + set_bit(JOB_SCAN_RESULTS,&ai->flags); + break; + } else if (ai->expires && + time_after_eq(jiffies,ai->expires)){ set_bit(JOB_AUTOWEP,&ai->flags); break; } if (!signal_pending(current)) { - schedule_timeout(ai->expires - jiffies); + unsigned long wake_at; + if (!ai->expires || !ai->scan_timeout) { + wake_at = max(ai->expires, + ai->scan_timeout); + } else { + wake_at = min(ai->expires, + ai->scan_timeout); + } + schedule_timeout(wake_at - jiffies); continue; } } else if (!signal_pending(current)) { @@ -2970,6 +3095,10 @@ static int airo_thread(void *data) { airo_send_event(dev); else if (test_bit(JOB_AUTOWEP, &ai->flags)) timer_func(dev); + else if (test_bit(JOB_SCAN_RESULTS, &ai->flags)) + airo_process_scan_results(ai); + else /* Shouldn't get here, but we make sure to unlock */ + up(&ai->sem); } complete_and_exit (&ai->thr_exited, 0); } @@ -3064,19 +3193,15 @@ static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) * and reassociations as valid status * Jean II */ if(newStatus == ASSOCIATED) { - if (apriv->scan_timestamp) { - /* Send an empty event to user space. - * We don't send the received data on - * the event because it would require - * us to do complex transcoding, and - * we want to minimise the work done in - * the irq handler. Use a request to - * extract the data - Jean II */ - wrqu.data.length = 0; - wrqu.data.flags = 0; - wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); - apriv->scan_timestamp = 0; +#if 0 + /* FIXME: Grabbing scan results here + * seems to be too early??? Just wait for + * timeout instead. */ + if (apriv->scan_timeout > 0) { + set_bit(JOB_SCAN_RESULTS, &apriv->flags); + wake_up_interruptible(&apriv->thr_wait); } +#endif if (down_trylock(&apriv->sem) != 0) { set_bit(JOB_EVENT, &apriv->flags); wake_up_interruptible(&apriv->thr_wait); @@ -6992,6 +7117,7 @@ static int airo_set_scan(struct net_device *dev, struct airo_info *ai = dev->priv; Cmd cmd; Resp rsp; + int wake = 0; /* Note : you may have realised that, as this is a SET operation, * this is privileged and therefore a normal user can't @@ -7001,17 +7127,25 @@ static int airo_set_scan(struct net_device *dev, * Jean II */ if (ai->flags & FLAG_RADIO_MASK) return -ENETDOWN; + if (down_interruptible(&ai->sem)) + return -ERESTARTSYS; + + /* If there's already a scan in progress, don't + * trigger another one. */ + if (ai->scan_timeout > 0) + goto out; + /* Initiate a scan command */ memset(&cmd, 0, sizeof(cmd)); cmd.cmd=CMD_LISTBSS; - if (down_interruptible(&ai->sem)) - return -ERESTARTSYS; issuecommand(ai, &cmd, &rsp); - ai->scan_timestamp = jiffies; - up(&ai->sem); - - /* At this point, just return to the user. */ + ai->scan_timeout = RUN_AT(3*HZ); + wake = 1; +out: + up(&ai->sem); + if (wake) + wake_up_interruptible(&ai->thr_wait); return 0; } @@ -7131,59 +7265,38 @@ static int airo_get_scan(struct net_device *dev, char *extra) { struct airo_info *ai = dev->priv; - BSSListRid BSSList; - int rc; + BSSListElement *net; + int err = 0; char *current_ev = extra; - /* When we are associated again, the scan has surely finished. - * Just in case, let's make sure enough time has elapsed since - * we started the scan. - Javier */ - if(ai->scan_timestamp && time_before(jiffies,ai->scan_timestamp+3*HZ)) { - /* Important note : we don't want to block the caller - * until results are ready for various reasons. - * First, managing wait queues is complex and racy - * (there may be multiple simultaneous callers). - * Second, we grab some rtnetlink lock before comming - * here (in dev_ioctl()). - * Third, the caller can wait on the Wireless Event - * - Jean II */ + /* If a scan is in-progress, return -EAGAIN */ + if (ai->scan_timeout > 0) return -EAGAIN; - } - ai->scan_timestamp = 0; - - /* There's only a race with proc_BSSList_open(), but its - * consequences are begnign. So I don't bother fixing it - Javier */ - /* Try to read the first entry of the scan result */ - rc = PC4500_readrid(ai, RID_BSSLISTFIRST, &BSSList, sizeof(BSSList), 1); - if((rc) || (BSSList.index == 0xffff)) { - /* Client error, no scan results... - * The caller need to restart the scan. */ - return -ENODATA; - } + if (down_interruptible(&ai->sem)) + return -EAGAIN; - /* Read and parse all entries */ - while((!rc) && (BSSList.index != 0xffff)) { + list_for_each_entry (net, &ai->network_list, list) { /* Translate to WE format this entry */ current_ev = airo_translate_scan(dev, current_ev, extra + dwrq->length, - &BSSList); + &net->bss); /* Check if there is space for one more entry */ if((extra + dwrq->length - current_ev) <= IW_EV_ADDR_LEN) { /* Ask user space to try again with a bigger buffer */ - return -E2BIG; + err = -E2BIG; + goto out; } - - /* Read next entry */ - rc = PC4500_readrid(ai, RID_BSSLISTNEXT, - &BSSList, sizeof(BSSList), 1); } + /* Length of data */ dwrq->length = (current_ev - extra); dwrq->flags = 0; /* todo */ - return 0; +out: + up(&ai->sem); + return err; } /*------------------------------------------------------------------*/ -- cgit v1.2.3 From 971d1e69229f3dfc6dd233b8f4b82df2c35eedd8 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 19 Mar 2006 19:21:44 -0800 Subject: [PATCH] hostap: Fix hw reset after CMDCODE_ACCESS_WRITE timeout The Coverity checker (CID: 59) noted that the call to prism2_hw_reset() was dead code. Move prism2_hw_reset() call to a place where it is actually executed. Signed-off-by: Adrian Bunk Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_hw.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index b1f142d9e23..328e9a1d13b 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -928,15 +928,15 @@ static int hfa384x_set_rid(struct net_device *dev, u16 rid, void *buf, int len) res = hfa384x_cmd(dev, HFA384X_CMDCODE_ACCESS_WRITE, rid, NULL, NULL); up(&local->rid_bap_sem); + if (res) { printk(KERN_DEBUG "%s: hfa384x_set_rid: CMDCODE_ACCESS_WRITE " "failed (res=%d, rid=%04x, len=%d)\n", dev->name, res, rid, len); - return res; - } - if (res == -ETIMEDOUT) - prism2_hw_reset(dev); + if (res == -ETIMEDOUT) + prism2_hw_reset(dev); + } return res; } -- cgit v1.2.3 From 54b85f489bdfafc9306dfcc21e0d2687c34c3b34 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sun, 19 Mar 2006 19:21:45 -0800 Subject: [PATCH] hostap: Fix ap_add_sta() return value verification The Coverity checker (CID: 273) spotted this inconsequent NULL checking (unconditionally dereferencing directly after checking for NULL isn't a good idea). Return immediately to avoid this. Signed-off-by: Adrian Bunk Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_ap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 753a1de6664..06c3fa32b31 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -3141,7 +3141,7 @@ int hostap_add_sta(struct ap_data *ap, u8 *sta_addr) if (ret == 1) { sta = ap_add_sta(ap, sta_addr); if (!sta) - ret = -1; + return -1; sta->flags = WLAN_STA_AUTH | WLAN_STA_ASSOC; sta->ap = 1; memset(sta->supported_rates, 0, sizeof(sta->supported_rates)); -- cgit v1.2.3 From 8abceaf1cf44b9d95bcc366fa277b33e292141c4 Mon Sep 17 00:00:00 2001 From: Eugene Teo Date: Sun, 19 Mar 2006 19:21:46 -0800 Subject: [PATCH] hostap: Fix double free in prism2_config() error path The Coverity checker (CID: 930) spotted this double free on error path (allocation failure). Do not free these here since generic error path will take care of this. Signed-off-by: Eugene Teo Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_cs.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index f8f4503475f..d335b250923 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -585,8 +585,6 @@ static int prism2_config(dev_link_t *link) parse = kmalloc(sizeof(cisparse_t), GFP_KERNEL); hw_priv = kmalloc(sizeof(*hw_priv), GFP_KERNEL); if (parse == NULL || hw_priv == NULL) { - kfree(parse); - kfree(hw_priv); ret = -ENOMEM; goto failed; } -- cgit v1.2.3 From 3a1c42ad98fddab63e62b400ae98e6f609485efc Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 19 Mar 2006 19:21:47 -0800 Subject: [PATCH] hostap: Fix unlikely read overrun in CIS parsing The Coverity checker (CID: 452, 453, 454, 455, 456) spotted this unlikely read overrun of CIS buffer. Abort if CISTPL_CONFIG or CISTPL_MANFID would not fit in buffer. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_plx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index 94fe2449f09..e258517ac85 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -368,7 +368,7 @@ static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len, switch (cis[pos]) { case CISTPL_CONFIG: - if (cis[pos + 1] < 1) + if (cis[pos + 1] < 2) goto cis_error; rmsz = (cis[pos + 2] & 0x3c) >> 2; rasz = cis[pos + 2] & 0x03; @@ -390,7 +390,7 @@ static int prism2_plx_check_cis(void __iomem *attr_mem, int attr_len, break; case CISTPL_MANFID: - if (cis[pos + 1] < 4) + if (cis[pos + 1] < 5) goto cis_error; manfid1 = cis[pos + 2] + (cis[pos + 3] << 8); manfid2 = cis[pos + 4] + (cis[pos + 5] << 8); -- cgit v1.2.3 From 4f7ecdf0b1b8125fe190247beb0df652829e13cb Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 19 Mar 2006 19:21:48 -0800 Subject: [PATCH] hostap: Remove dead code (duplicated idx != 0) The Coverity checker (CID: 58) spotted this duplicated idx != 0 validation for unicast keys in prism2_ioctl_siwencodeext(). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_ioctl.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index f3e0ce1ee03..8b37e824dfc 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -3358,10 +3358,6 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { if (!sta_ptr) local->tx_keyidx = i; - else if (i) { - ret = -EINVAL; - goto done; - } } -- cgit v1.2.3 From 9320199957cebc39ccef372fa1fccf5ba3d3fd7d Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 19 Mar 2006 19:21:49 -0800 Subject: [PATCH] hostap: Fix memory leak on PCI probe error path The Coverity checker (CID: 659, 660) spotted this resource leak on PCI probe error path. Free private data structure if pci_enable_device() fails. Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_pci.c | 4 +++- drivers/net/wireless/hostap/hostap_plx.c | 9 +++++---- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index 2e85bdced2d..194f0709758 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -307,7 +307,7 @@ static int prism2_pci_probe(struct pci_dev *pdev, memset(hw_priv, 0, sizeof(*hw_priv)); if (pci_enable_device(pdev)) - return -EIO; + goto err_out_free; phymem = pci_resource_start(pdev, 0); @@ -368,6 +368,8 @@ static int prism2_pci_probe(struct pci_dev *pdev, err_out_disable: pci_disable_device(pdev); prism2_free_local_data(dev); + + err_out_free: kfree(hw_priv); return -ENODEV; diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index e258517ac85..edaaa943eb8 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -452,7 +452,7 @@ static int prism2_plx_probe(struct pci_dev *pdev, memset(hw_priv, 0, sizeof(*hw_priv)); if (pci_enable_device(pdev)) - return -EIO; + goto err_out_free; /* National Datacomm NCP130 based on TMD7160, not PLX9052. */ tmd7160 = (pdev->vendor == 0x15e8) && (pdev->device == 0x0131); @@ -567,9 +567,6 @@ static int prism2_plx_probe(struct pci_dev *pdev, return hostap_hw_ready(dev); fail: - prism2_free_local_data(dev); - kfree(hw_priv); - if (irq_registered && dev) free_irq(dev->irq, dev); @@ -577,6 +574,10 @@ static int prism2_plx_probe(struct pci_dev *pdev, iounmap(attr_mem); pci_disable_device(pdev); + prism2_free_local_data(dev); + + err_out_free: + kfree(hw_priv); return -ENODEV; } -- cgit v1.2.3 From d26045404c8925eadf252aeb6b5b8055fc01e9de Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 23 Mar 2006 08:51:36 -0800 Subject: [PATCH] sky2: typo in last stats patch Typo in last stats patch. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 36db93811ac..78c210facaa 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2484,7 +2484,7 @@ static const struct sky2_stat { { "single_collisions", GM_TXF_SNG_COL }, { "multi_collisions", GM_TXF_MUL_COL }, - { "rx_short", GM_RXE_SHT }, + { "rx_short", GM_RXF_SHT }, { "rx_runt", GM_RXE_FRAG }, { "rx_64_byte_packets", GM_RXF_64B }, { "rx_65_to_127_byte_packets", GM_RXF_127B }, -- cgit v1.2.3 From 050ff18016979b98e3cadb930d6e29bfd5530469 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 23 Mar 2006 08:51:37 -0800 Subject: [PATCH] sky2: Fix RX stats Unicast packets are shown as multicast, real multicast packets are missing. Signed-off-by: Patrick McHardy Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 78c210facaa..f3f70b07576 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -2607,7 +2607,7 @@ static struct net_device_stats *sky2_get_stats(struct net_device *dev) sky2->net_stats.rx_bytes = data[1]; sky2->net_stats.tx_packets = data[2] + data[4] + data[6]; sky2->net_stats.rx_packets = data[3] + data[5] + data[7]; - sky2->net_stats.multicast = data[5] + data[7]; + sky2->net_stats.multicast = data[3] + data[5]; sky2->net_stats.collisions = data[10]; sky2->net_stats.tx_aborted_errors = data[12]; -- cgit v1.2.3 From 15240072ac3ffb67050acd0b71b477c3bb977670 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 23 Mar 2006 08:51:38 -0800 Subject: [PATCH] sky2: dont need to use dev_kfree_skb_any Transmit buffers are always freed with interrupts enabled (softirq), so we can just call dev_kfree_skb. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/sky2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index f3f70b07576..68f9c206a62 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -1175,7 +1175,7 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev) /* just drop the packet if non-linear expansion fails */ if (skb_header_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); goto out_unlock; } @@ -1324,7 +1324,7 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done) PCI_DMA_TODEVICE); } - dev_kfree_skb_any(skb); + dev_kfree_skb(skb); } sky2->tx_cons = put; -- cgit v1.2.3 From 901ccefb2dd7fe6a9e750a68f990f2a7d76b78d2 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 23 Mar 2006 11:07:23 -0800 Subject: [PATCH] skge: align receive buffers The skge driver aligns the header on the initial receive buffers, but but doesn't on followon receive buffer allocations. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 4eda81d41b1..89a6252ac7c 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2155,7 +2155,7 @@ static int skge_up(struct net_device *dev) printk(KERN_INFO PFX "%s: enabling interface\n", dev->name); if (dev->mtu > RX_BUF_SIZE) - skge->rx_buf_size = dev->mtu + ETH_HLEN + NET_IP_ALIGN; + skge->rx_buf_size = dev->mtu + ETH_HLEN; else skge->rx_buf_size = RX_BUF_SIZE; @@ -2611,6 +2611,7 @@ static inline struct sk_buff *skge_rx_get(struct skge_port *skge, if (!nskb) goto resubmit; + skb_reserve(nskb, NET_IP_ALIGN); pci_unmap_single(skge->hw->pdev, pci_unmap_addr(e, mapaddr), pci_unmap_len(e, maplen), -- cgit v1.2.3 From b5d56ddc3f839e94e97a3eb8afb4d0d64a9f2ef8 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 23 Mar 2006 11:07:24 -0800 Subject: [PATCH] skge: dont use dev_alloc_skb for rx buffs The skge driver was using dev_alloc_skb which reserves space for the Ethernet header. This unnecessary and it should just use alloc_skb, also by using GFP_KERNEL during startup it won't run into problems when a user asks for a huge ring size or mtu and potentially drains the reserved atomic pool. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 89a6252ac7c..b0aa150bbd8 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -829,7 +829,7 @@ static int skge_rx_fill(struct skge_port *skge) do { struct sk_buff *skb; - skb = dev_alloc_skb(skge->rx_buf_size + NET_IP_ALIGN); + skb = alloc_skb(skge->rx_buf_size + NET_IP_ALIGN, GFP_KERNEL); if (!skb) return -ENOMEM; @@ -2592,7 +2592,7 @@ static inline struct sk_buff *skge_rx_get(struct skge_port *skge, goto error; if (len < RX_COPY_THRESHOLD) { - skb = dev_alloc_skb(len + 2); + skb = alloc_skb(len + 2, GFP_ATOMIC); if (!skb) goto resubmit; @@ -2607,7 +2607,7 @@ static inline struct sk_buff *skge_rx_get(struct skge_port *skge, skge_rx_reuse(e, skge->rx_buf_size); } else { struct sk_buff *nskb; - nskb = dev_alloc_skb(skge->rx_buf_size + NET_IP_ALIGN); + nskb = alloc_skb(skge->rx_buf_size + NET_IP_ALIGN, GFP_ATOMIC); if (!nskb) goto resubmit; -- cgit v1.2.3 From 5a01144717ee9dacd45e1b0861a2c593796bcead Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 23 Mar 2006 11:07:25 -0800 Subject: [PATCH] skge: rx_reuse called twice In the error case we call skge_rx_reuse twice. This is harmless but unnecessary. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index b0aa150bbd8..72148f0fbfc 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -781,7 +781,7 @@ static void skge_rx_setup(struct skge_port *skge, struct skge_element *e, * Note: DMA address is not changed by chip. * MTU not changed while receiver active. */ -static void skge_rx_reuse(struct skge_element *e, unsigned int size) +static inline void skge_rx_reuse(struct skge_element *e, unsigned int size) { struct skge_rx_desc *rd = e->desc; @@ -2719,8 +2719,7 @@ static int skge_poll(struct net_device *dev, int *budget) netif_receive_skb(skb); ++work_done; - } else - skge_rx_reuse(e, skge->rx_buf_size); + } } ring->to_clean = e; -- cgit v1.2.3 From 4c180fc424550217344db6fe8960732dbd7feb0c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 23 Mar 2006 11:07:26 -0800 Subject: [PATCH] skge: multicast statistics fix Fix count of multicast packets. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 72148f0fbfc..e15cbefcb6e 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -357,7 +357,7 @@ static struct net_device_stats *skge_get_stats(struct net_device *dev) skge->net_stats.rx_bytes = data[1]; skge->net_stats.tx_packets = data[2] + data[4] + data[6]; skge->net_stats.rx_packets = data[3] + data[5] + data[7]; - skge->net_stats.multicast = data[5] + data[7]; + skge->net_stats.multicast = data[3] + data[5]; skge->net_stats.collisions = data[10]; skge->net_stats.tx_aborted_errors = data[12]; -- cgit v1.2.3 From 866b4f3e94a7568a1cb0018c061e19e120de6922 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 23 Mar 2006 11:07:27 -0800 Subject: [PATCH] skge: dont free skb until multi-part transmit complete Don't free transmit buffers until the whole set of transmit descriptors has been marked as done. Otherwise, we risk freeing a skb before the whole transmit is done. This changes the transmit completion handling from incremental to a two pass algorithm. First pass scans and records the start of the last done descriptor, second cleans up until that point. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 73 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 38 insertions(+), 35 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index e15cbefcb6e..a261766bc05 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -2404,35 +2404,39 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static inline void skge_tx_free(struct skge_hw *hw, struct skge_element *e) -{ - /* This ring element can be skb or fragment */ - if (e->skb) { - pci_unmap_single(hw->pdev, - pci_unmap_addr(e, mapaddr), - pci_unmap_len(e, maplen), - PCI_DMA_TODEVICE); - dev_kfree_skb(e->skb); +static void skge_tx_complete(struct skge_port *skge, struct skge_element *last) +{ + struct pci_dev *pdev = skge->hw->pdev; + struct skge_element *e; + + for (e = skge->tx_ring.to_clean; e != last; e = e->next) { + struct sk_buff *skb = e->skb; + int i; + e->skb = NULL; - } else { - pci_unmap_page(hw->pdev, - pci_unmap_addr(e, mapaddr), - pci_unmap_len(e, maplen), - PCI_DMA_TODEVICE); + pci_unmap_single(pdev, pci_unmap_addr(e, mapaddr), + skb_headlen(skb), PCI_DMA_TODEVICE); + ++skge->tx_avail; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + e = e->next; + pci_unmap_page(pdev, pci_unmap_addr(e, mapaddr), + skb_shinfo(skb)->frags[i].size, + PCI_DMA_TODEVICE); + ++skge->tx_avail; + } + + dev_kfree_skb(skb); } + skge->tx_ring.to_clean = e; } static void skge_tx_clean(struct skge_port *skge) { - struct skge_ring *ring = &skge->tx_ring; - struct skge_element *e; spin_lock_bh(&skge->tx_lock); - for (e = ring->to_clean; e != ring->to_use; e = e->next) { - ++skge->tx_avail; - skge_tx_free(skge->hw, e); - } - ring->to_clean = e; + skge_tx_complete(skge, skge->tx_ring.to_use); + netif_wake_queue(skge->netdev); spin_unlock_bh(&skge->tx_lock); } @@ -2662,27 +2666,26 @@ resubmit: static void skge_tx_done(struct skge_port *skge) { struct skge_ring *ring = &skge->tx_ring; - struct skge_element *e; + struct skge_element *e, *last; spin_lock(&skge->tx_lock); - for (e = ring->to_clean; prefetch(e->next), e != ring->to_use; e = e->next) { + last = ring->to_clean; + for (e = ring->to_clean; e != ring->to_use; e = e->next) { struct skge_tx_desc *td = e->desc; - u32 control; - rmb(); - control = td->control; - if (control & BMU_OWN) + if (td->control & BMU_OWN) break; - if (unlikely(netif_msg_tx_done(skge))) - printk(KERN_DEBUG PFX "%s: tx done slot %td status 0x%x\n", - skge->netdev->name, e - ring->start, td->status); - - skge_tx_free(skge->hw, e); - e->skb = NULL; - ++skge->tx_avail; + if (td->control & BMU_EOF) { + last = e->next; + if (unlikely(netif_msg_tx_done(skge))) + printk(KERN_DEBUG PFX "%s: tx done slot %td\n", + skge->netdev->name, e - ring->start); + } } - ring->to_clean = e; + + skge_tx_complete(skge, last); + skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); if (skge->tx_avail > MAX_SKB_FRAGS + 1) -- cgit v1.2.3 From 29b4e886cbba5e0b0e4379fea7fc313e7808b5c2 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 23 Mar 2006 11:07:28 -0800 Subject: [PATCH] skge: compute available ring buffers Don't need to keep track of available buffers, it is simpler to just compute the value (ala e1000). Don't need tes on link up because should always have available buffers then. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 20 ++++++++++---------- drivers/net/skge.h | 1 - 2 files changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index a261766bc05..a6f42fc8573 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -847,8 +847,7 @@ static void skge_link_up(struct skge_port *skge) LED_BLK_OFF|LED_SYNC_OFF|LED_ON); netif_carrier_on(skge->netdev); - if (skge->tx_avail > MAX_SKB_FRAGS + 1) - netif_wake_queue(skge->netdev); + netif_wake_queue(skge->netdev); if (netif_msg_link(skge)) printk(KERN_INFO PFX @@ -2190,8 +2189,6 @@ static int skge_up(struct net_device *dev) if (err) goto free_rx_ring; - skge->tx_avail = skge->tx_ring.count - 1; - /* Initialize MAC */ spin_lock_bh(&hw->phy_lock); if (hw->chip_id == CHIP_ID_GENESIS) @@ -2294,6 +2291,12 @@ static int skge_down(struct net_device *dev) return 0; } +static inline int skge_avail(const struct skge_ring *ring) +{ + return ((ring->to_clean > ring->to_use) ? 0 : ring->count) + + (ring->to_clean - ring->to_use) - 1; +} + static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) { struct skge_port *skge = netdev_priv(dev); @@ -2314,7 +2317,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_LOCKED; } - if (unlikely(skge->tx_avail < skb_shinfo(skb)->nr_frags +1)) { + if (unlikely(skge_avail(&skge->tx_ring) < skb_shinfo(skb)->nr_frags + 1)) { if (!netif_queue_stopped(dev)) { netif_stop_queue(dev); @@ -2390,8 +2393,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) dev->name, e - ring->start, skb->len); ring->to_use = e->next; - skge->tx_avail -= skb_shinfo(skb)->nr_frags + 1; - if (skge->tx_avail <= MAX_SKB_FRAGS + 1) { + if (skge_avail(&skge->tx_ring) <= MAX_SKB_FRAGS + 1) { pr_debug("%s: transmit queue full\n", dev->name); netif_stop_queue(dev); } @@ -2416,14 +2418,12 @@ static void skge_tx_complete(struct skge_port *skge, struct skge_element *last) e->skb = NULL; pci_unmap_single(pdev, pci_unmap_addr(e, mapaddr), skb_headlen(skb), PCI_DMA_TODEVICE); - ++skge->tx_avail; for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { e = e->next; pci_unmap_page(pdev, pci_unmap_addr(e, mapaddr), skb_shinfo(skb)->frags[i].size, PCI_DMA_TODEVICE); - ++skge->tx_avail; } dev_kfree_skb(skb); @@ -2688,7 +2688,7 @@ static void skge_tx_done(struct skge_port *skge) skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); - if (skge->tx_avail > MAX_SKB_FRAGS + 1) + if (skge_avail(&skge->tx_ring) > MAX_SKB_FRAGS + 1) netif_wake_queue(skge->netdev); spin_unlock(&skge->tx_lock); diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 2efdacc290e..1f1ce88c818 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h @@ -2418,7 +2418,6 @@ struct skge_port { int port; spinlock_t tx_lock; - u32 tx_avail; struct skge_ring tx_ring; struct skge_ring rx_ring; -- cgit v1.2.3 From eff4b1fe0aa8002cbf414576e8cc102967bd9d5d Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Thu, 23 Mar 2006 11:07:29 -0800 Subject: [PATCH] skge: version 1.5 Update version to allow tracking of complaints. Signed-off-by: Stephen Hemminger Signed-off-by: Jeff Garzik --- drivers/net/skge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/skge.c b/drivers/net/skge.c index a6f42fc8573..35dbf05c7f0 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -44,7 +44,7 @@ #include "skge.h" #define DRV_NAME "skge" -#define DRV_VERSION "1.4" +#define DRV_VERSION "1.5" #define PFX DRV_NAME " " #define DEFAULT_TX_RING_SIZE 128 -- cgit v1.2.3 From b336cea307839f97684d314071ef683821c571ed Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 24 Mar 2006 03:15:40 -0800 Subject: [PATCH] remove ISA legacy functions: drivers/net/hp-plus.c switch to ioremap() Adrian Bunk: The order of the hunks in the patch was slightly rearranged due to an unrelated change in the driver. Signed-off-by: Al Viro Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/hp-plus.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index 74e167e7dea..0d7a6250e34 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -250,6 +250,12 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) ei_status.block_output = &hpp_mem_block_output; ei_status.get_8390_hdr = &hpp_mem_get_8390_hdr; dev->mem_start = mem_start; + ei_status.mem = ioremap(mem_start, + (HP_STOP_PG - HP_START_PG)*256); + if (!ei_status.mem) { + retval = -ENOMEM; + goto out; + } ei_status.rmem_start = dev->mem_start + TX_PAGES/2*256; dev->mem_end = ei_status.rmem_end = dev->mem_start + (HP_STOP_PG - HP_START_PG)*256; @@ -262,8 +268,10 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) retval = register_netdev(dev); if (retval) - goto out; + goto out1; return 0; +out1: + iounmap(ei_status.mem); out: release_region(ioaddr, HP_IO_EXTENT); return retval; @@ -372,7 +380,7 @@ hpp_mem_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring outw((ring_page<<8), ioaddr + HPP_IN_ADDR); outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION); - isa_memcpy_fromio(hdr, dev->mem_start, sizeof(struct e8390_pkt_hdr)); + memcpy_fromio(hdr, ei_status.mem, sizeof(struct e8390_pkt_hdr)); outw(option_reg, ioaddr + HPP_OPTION); hdr->count = (le16_to_cpu(hdr->count) + 3) & ~3; /* Round up allocation. */ } @@ -391,7 +399,7 @@ hpp_mem_block_input(struct net_device *dev, int count, struct sk_buff *skb, int Also note that we *can't* use eth_io_copy_and_sum() because it will not always copy "count" bytes (e.g. padded IP). */ - isa_memcpy_fromio(skb->data, dev->mem_start, count); + memcpy_fromio(skb->data, ei_status.mem, count); outw(option_reg, ioaddr + HPP_OPTION); } @@ -416,7 +424,7 @@ hpp_mem_block_output(struct net_device *dev, int count, outw(start_page << 8, ioaddr + HPP_OUT_ADDR); outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION); - isa_memcpy_toio(dev->mem_start, buf, (count + 3) & ~3); + memcpy_toio(ei_status.mem, buf, (count + 3) & ~3); outw(option_reg, ioaddr + HPP_OPTION); return; @@ -470,6 +478,7 @@ init_module(void) static void cleanup_card(struct net_device *dev) { /* NB: hpp_close() handles free_irq */ + iounmap(ei_status.mem); release_region(dev->base_addr - NIC_OFFSET, HP_IO_EXTENT); } -- cgit v1.2.3 From c44fec118b62baad3fc70e2ef3447729a1d9b194 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 24 Mar 2006 03:15:41 -0800 Subject: [PATCH] remove ISA legacy functions: drivers/net/lance.c switch to ioremap() Signed-off-by: Al Viro Signed-off-by: Adrian Bunk Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/lance.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/lance.c b/drivers/net/lance.c index d1d714faa6c..bb5ad479210 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -464,20 +464,25 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int static int did_version; /* Already printed version info. */ unsigned long flags; int err = -ENOMEM; + void __iomem *bios; /* First we look for special cases. Check for HP's on-board ethernet by looking for 'HP' in the BIOS. There are two HP versions, check the BIOS for the configuration port. This method provided by L. Julliard, Laurent_Julliard@grenoble.hp.com. */ - if (isa_readw(0x000f0102) == 0x5048) { + bios = ioremap(0xf00f0, 0x14); + if (!bios) + return -ENOMEM; + if (readw(bios + 0x12) == 0x5048) { static const short ioaddr_table[] = { 0x300, 0x320, 0x340, 0x360}; - int hp_port = (isa_readl(0x000f00f1) & 1) ? 0x499 : 0x99; + int hp_port = (readl(bios + 1) & 1) ? 0x499 : 0x99; /* We can have boards other than the built-in! Verify this is on-board. */ if ((inb(hp_port) & 0xc0) == 0x80 && ioaddr_table[inb(hp_port) & 3] == ioaddr) hp_builtin = hp_port; } + iounmap(bios); /* We also recognize the HP Vectra on-board here, but check below. */ hpJ2405A = (inb(ioaddr) == 0x08 && inb(ioaddr+1) == 0x00 && inb(ioaddr+2) == 0x09); -- cgit v1.2.3 From 53b3531bbbf70ac7551b32d1acc229d94de52658 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Fri, 24 Mar 2006 03:16:13 -0800 Subject: [PATCH] s/;;/;/g Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/sk98lin/skge.c | 2 +- drivers/net/sky2.h | 2 +- drivers/net/wireless/prism54/oid_mgt.c | 4 ++-- drivers/net/wireless/spectrum_cs.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index a5f2b1ee075..38a26df4095 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c @@ -1727,7 +1727,7 @@ struct sk_buff *pMessage) /* pointer to send-message */ pTxd->VDataHigh = (SK_U32) (PhysAddr >> 32); pTxd->pMBuf = pMessage; - pTxd->TBControl = Control | BMU_OWN | sk_frag->size;; + pTxd->TBControl = Control | BMU_OWN | sk_frag->size; /* ** Do we have the last fragment? diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h index 2838f661b39..62532b4e45c 100644 --- a/drivers/net/sky2.h +++ b/drivers/net/sky2.h @@ -1804,7 +1804,7 @@ struct sky2_rx_le { __le16 length; u8 ctrl; u8 opcode; -} __attribute((packed));; +} __attribute((packed)); struct sky2_status_le { __le32 status; /* also checksum */ diff --git a/drivers/net/wireless/prism54/oid_mgt.c b/drivers/net/wireless/prism54/oid_mgt.c index eea2f04c8c6..ebb23878583 100644 --- a/drivers/net/wireless/prism54/oid_mgt.c +++ b/drivers/net/wireless/prism54/oid_mgt.c @@ -332,7 +332,7 @@ mgt_le_to_cpu(int type, void *data) case OID_TYPE_ATTACH:{ struct obj_attachment *attach = data; attach->id = le16_to_cpu(attach->id); - attach->size = le16_to_cpu(attach->size);; + attach->size = le16_to_cpu(attach->size); break; } case OID_TYPE_SSID: @@ -401,7 +401,7 @@ mgt_cpu_to_le(int type, void *data) case OID_TYPE_ATTACH:{ struct obj_attachment *attach = data; attach->id = cpu_to_le16(attach->id); - attach->size = cpu_to_le16(attach->size);; + attach->size = cpu_to_le16(attach->size); break; } case OID_TYPE_SSID: diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index fee4be1ce81..5fa6fbe35bb 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c @@ -147,7 +147,7 @@ struct pdi { __le16 _len; /* length of ID and data, in words */ __le16 _id; /* record ID */ char data[0]; /* plug data */ -} __attribute__ ((packed));; +} __attribute__ ((packed)); /* Functions for access to little-endian data */ -- cgit v1.2.3 From 10e705f83c3e796893a70fb872895ba604901166 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 24 Mar 2006 03:18:23 -0800 Subject: [PATCH] Fix "value computed not used" warnings Fixes for annoying gcc-4.1 compile warnings "value computed not used". Simply cast to void. (akpm: Linus will go ballistic...) Signed-off-by: Takashi Iwai Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/8139too.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index f5ee064ab6b..feae7832fc8 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -1131,7 +1131,7 @@ static void __devexit rtl8139_remove_one (struct pci_dev *pdev) No extra delay is needed with 33Mhz PCI, but 66Mhz may change this. */ -#define eeprom_delay() RTL_R32(Cfg9346) +#define eeprom_delay() (void)RTL_R32(Cfg9346) /* The EEPROM commands include the alway-set leading bit. */ #define EE_WRITE_CMD (5) -- cgit v1.2.3 From d4b7780ea1d2e08410fcc9963a57254147ae577a Mon Sep 17 00:00:00 2001 From: Andrew Victor Date: Fri, 24 Mar 2006 11:50:17 +0200 Subject: [PATCH] AT91RM9200 Ethernet driver This patch adds support for the Ethernet controller integrated in the Atmel AT91RM9200 SoC processor. Changes since the previous submission (01/02/2006) are: - Make use of the clk.h clock infrastructure. - The multicast hash function is not crc32. [Patch by Pedro Perez] Signed-off-by: Andrew Victor Signed-off-by: Jeff Garzik --- drivers/net/arm/Kconfig | 8 + drivers/net/arm/Makefile | 1 + drivers/net/arm/at91_ether.c | 1110 ++++++++++++++++++++++++++++++++++++++++++ drivers/net/arm/at91_ether.h | 101 ++++ 4 files changed, 1220 insertions(+) create mode 100644 drivers/net/arm/at91_ether.c create mode 100644 drivers/net/arm/at91_ether.h (limited to 'drivers/net') diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig index 625184b65e3..77fe20dbea3 100644 --- a/drivers/net/arm/Kconfig +++ b/drivers/net/arm/Kconfig @@ -31,3 +31,11 @@ config ARM_ETHERH help If you have an Acorn system with one of these network cards, you should say Y to this option if you wish to use it with Linux. + +config ARM_AT91_ETHER + tristate "AT91RM9200 Ethernet support" + depends on NET_ETHERNET && ARM && ARCH_AT91RM9200 + select MII + help + If you wish to compile a kernel for the AT91RM9200 and enable + ethernet support, then you should always answer Y to this. diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile index bc263edf06a..42c95b79c26 100644 --- a/drivers/net/arm/Makefile +++ b/drivers/net/arm/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o obj-$(CONFIG_ARM_ETHERH) += etherh.o obj-$(CONFIG_ARM_ETHER3) += ether3.o obj-$(CONFIG_ARM_ETHER1) += ether1.o +obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c new file mode 100644 index 00000000000..5503dc8a66e --- /dev/null +++ b/drivers/net/arm/at91_ether.c @@ -0,0 +1,1110 @@ +/* + * Ethernet driver for the Atmel AT91RM9200 (Thunder) + * + * Copyright (C) 2003 SAN People (Pty) Ltd + * + * Based on an earlier Atmel EMAC macrocell driver by Atmel and Lineo Inc. + * Initial version by Rick Bronson 01/11/2003 + * + * Intel LXT971A PHY support by Christopher Bahns & David Knickerbocker + * (Polaroid Corporation) + * + * Realtek RTL8201(B)L PHY support by Roman Avramenko + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include "at91_ether.h" + +#define DRV_NAME "at91_ether" +#define DRV_VERSION "1.0" + +static struct net_device *at91_dev; +static struct clk *ether_clk; + +/* ..................................................................... */ + +/* + * Read from a EMAC register. + */ +static inline unsigned long at91_emac_read(unsigned int reg) +{ + void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC; + + return __raw_readl(emac_base + reg); +} + +/* + * Write to a EMAC register. + */ +static inline void at91_emac_write(unsigned int reg, unsigned long value) +{ + void __iomem *emac_base = (void __iomem *)AT91_VA_BASE_EMAC; + + __raw_writel(value, emac_base + reg); +} + +/* ........................... PHY INTERFACE ........................... */ + +/* + * Enable the MDIO bit in MAC control register + * When not called from an interrupt-handler, access to the PHY must be + * protected by a spinlock. + */ +static void enable_mdi(void) +{ + unsigned long ctl; + + ctl = at91_emac_read(AT91_EMAC_CTL); + at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_MPE); /* enable management port */ +} + +/* + * Disable the MDIO bit in the MAC control register + */ +static void disable_mdi(void) +{ + unsigned long ctl; + + ctl = at91_emac_read(AT91_EMAC_CTL); + at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_MPE); /* disable management port */ +} + +/* + * Wait until the PHY operation is complete. + */ +static inline void at91_phy_wait(void) { + unsigned long timeout = jiffies + 2; + + while (!(at91_emac_read(AT91_EMAC_SR) & AT91_EMAC_SR_IDLE)) { + if (time_after(jiffies, timeout)) { + printk("at91_ether: MIO timeout\n"); + break; + } + cpu_relax(); + } +} + +/* + * Write value to the a PHY register + * Note: MDI interface is assumed to already have been enabled. + */ +static void write_phy(unsigned char phy_addr, unsigned char address, unsigned int value) +{ + at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_W + | ((phy_addr & 0x1f) << 23) | (address << 18) | (value & AT91_EMAC_DATA)); + + /* Wait until IDLE bit in Network Status register is cleared */ + at91_phy_wait(); +} + +/* + * Read value stored in a PHY register. + * Note: MDI interface is assumed to already have been enabled. + */ +static void read_phy(unsigned char phy_addr, unsigned char address, unsigned int *value) +{ + at91_emac_write(AT91_EMAC_MAN, AT91_EMAC_MAN_802_3 | AT91_EMAC_RW_R + | ((phy_addr & 0x1f) << 23) | (address << 18)); + + /* Wait until IDLE bit in Network Status register is cleared */ + at91_phy_wait(); + + *value = at91_emac_read(AT91_EMAC_MAN) & AT91_EMAC_DATA; +} + +/* ........................... PHY MANAGEMENT .......................... */ + +/* + * Access the PHY to determine the current link speed and mode, and update the + * MAC accordingly. + * If no link or auto-negotiation is busy, then no changes are made. + */ +static void update_linkspeed(struct net_device *dev) +{ + struct at91_private *lp = (struct at91_private *) dev->priv; + unsigned int bmsr, bmcr, lpa, mac_cfg; + unsigned int speed, duplex; + + if (!mii_link_ok(&lp->mii)) { /* no link */ + netif_carrier_off(dev); + printk(KERN_INFO "%s: Link down.\n", dev->name); + return; + } + + /* Link up, or auto-negotiation still in progress */ + read_phy(lp->phy_address, MII_BMSR, &bmsr); + read_phy(lp->phy_address, MII_BMCR, &bmcr); + if (bmcr & BMCR_ANENABLE) { /* AutoNegotiation is enabled */ + if (!(bmsr & BMSR_ANEGCOMPLETE)) + return; /* Do nothing - another interrupt generated when negotiation complete */ + + read_phy(lp->phy_address, MII_LPA, &lpa); + if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF)) speed = SPEED_100; + else speed = SPEED_10; + if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL)) duplex = DUPLEX_FULL; + else duplex = DUPLEX_HALF; + } else { + speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10; + duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; + } + + /* Update the MAC */ + mac_cfg = at91_emac_read(AT91_EMAC_CFG) & ~(AT91_EMAC_SPD | AT91_EMAC_FD); + if (speed == SPEED_100) { + if (duplex == DUPLEX_FULL) /* 100 Full Duplex */ + mac_cfg |= AT91_EMAC_SPD | AT91_EMAC_FD; + else /* 100 Half Duplex */ + mac_cfg |= AT91_EMAC_SPD; + } else { + if (duplex == DUPLEX_FULL) /* 10 Full Duplex */ + mac_cfg |= AT91_EMAC_FD; + else {} /* 10 Half Duplex */ + } + at91_emac_write(AT91_EMAC_CFG, mac_cfg); + + printk(KERN_INFO "%s: Link now %i-%s\n", dev->name, speed, (duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex"); + netif_carrier_on(dev); +} + +/* + * Handle interrupts from the PHY + */ +static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct at91_private *lp = (struct at91_private *) dev->priv; + unsigned int phy; + + /* + * This hander is triggered on both edges, but the PHY chips expect + * level-triggering. We therefore have to check if the PHY actually has + * an IRQ pending. + */ + enable_mdi(); + if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { + read_phy(lp->phy_address, MII_DSINTR_REG, &phy); /* ack interrupt in Davicom PHY */ + if (!(phy & (1 << 0))) + goto done; + } + else if (lp->phy_type == MII_LXT971A_ID) { + read_phy(lp->phy_address, MII_ISINTS_REG, &phy); /* ack interrupt in Intel PHY */ + if (!(phy & (1 << 2))) + goto done; + } + else if (lp->phy_type == MII_BCM5221_ID) { + read_phy(lp->phy_address, MII_BCMINTR_REG, &phy); /* ack interrupt in Broadcom PHY */ + if (!(phy & (1 << 0))) + goto done; + } + else if (lp->phy_type == MII_KS8721_ID) { + read_phy(lp->phy_address, MII_TPISTATUS, &phy); /* ack interrupt in Micrel PHY */ + if (!(phy & ((1 << 2) | 1))) + goto done; + } + + update_linkspeed(dev); + +done: + disable_mdi(); + + return IRQ_HANDLED; +} + +/* + * Initialize and enable the PHY interrupt for link-state changes + */ +static void enable_phyirq(struct net_device *dev) +{ + struct at91_private *lp = (struct at91_private *) dev->priv; + unsigned int dsintr, irq_number; + int status; + + if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */ + return; + if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */ + return; + if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */ + return; + + irq_number = lp->board_data.phy_irq_pin; + status = request_irq(irq_number, at91ether_phy_interrupt, 0, dev->name, dev); + if (status) { + printk(KERN_ERR "at91_ether: PHY IRQ %d request failed - status %d!\n", irq_number, status); + return; + } + + spin_lock_irq(&lp->lock); + enable_mdi(); + + if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */ + read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr); + dsintr = dsintr & ~0xf00; /* clear bits 8..11 */ + write_phy(lp->phy_address, MII_DSINTR_REG, dsintr); + } + else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */ + read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr); + dsintr = dsintr | 0xf2; /* set bits 1, 4..7 */ + write_phy(lp->phy_address, MII_ISINTE_REG, dsintr); + } + else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */ + dsintr = (1 << 15) | ( 1 << 14); + write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr); + } + else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */ + dsintr = (1 << 10) | ( 1 << 8); + write_phy(lp->phy_address, MII_TPISTATUS, dsintr); + } + + disable_mdi(); + spin_unlock_irq(&lp->lock); +} + +/* + * Disable the PHY interrupt + */ +static void disable_phyirq(struct net_device *dev) +{ + struct at91_private *lp = (struct at91_private *) dev->priv; + unsigned int dsintr; + unsigned int irq_number; + + if (lp->phy_type == MII_RTL8201_ID) /* RTL8201 does not have an interrupt */ + return; + if (lp->phy_type == MII_DP83847_ID) /* DP83847 does not have an interrupt */ + return; + if (lp->phy_type == MII_AC101L_ID) /* AC101L interrupt not supported yet */ + return; + + spin_lock_irq(&lp->lock); + enable_mdi(); + + if ((lp->phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { /* for Davicom PHY */ + read_phy(lp->phy_address, MII_DSINTR_REG, &dsintr); + dsintr = dsintr | 0xf00; /* set bits 8..11 */ + write_phy(lp->phy_address, MII_DSINTR_REG, dsintr); + } + else if (lp->phy_type == MII_LXT971A_ID) { /* for Intel PHY */ + read_phy(lp->phy_address, MII_ISINTE_REG, &dsintr); + dsintr = dsintr & ~0xf2; /* clear bits 1, 4..7 */ + write_phy(lp->phy_address, MII_ISINTE_REG, dsintr); + } + else if (lp->phy_type == MII_BCM5221_ID) { /* for Broadcom PHY */ + read_phy(lp->phy_address, MII_BCMINTR_REG, &dsintr); + dsintr = ~(1 << 14); + write_phy(lp->phy_address, MII_BCMINTR_REG, dsintr); + } + else if (lp->phy_type == MII_KS8721_ID) { /* for Micrel PHY */ + read_phy(lp->phy_address, MII_TPISTATUS, &dsintr); + dsintr = ~((1 << 10) | (1 << 8)); + write_phy(lp->phy_address, MII_TPISTATUS, dsintr); + } + + disable_mdi(); + spin_unlock_irq(&lp->lock); + + irq_number = lp->board_data.phy_irq_pin; + free_irq(irq_number, dev); /* Free interrupt handler */ +} + +/* + * Perform a software reset of the PHY. + */ +#if 0 +static void reset_phy(struct net_device *dev) +{ + struct at91_private *lp = (struct at91_private *) dev->priv; + unsigned int bmcr; + + spin_lock_irq(&lp->lock); + enable_mdi(); + + /* Perform PHY reset */ + write_phy(lp->phy_address, MII_BMCR, BMCR_RESET); + + /* Wait until PHY reset is complete */ + do { + read_phy(lp->phy_address, MII_BMCR, &bmcr); + } while (!(bmcr && BMCR_RESET)); + + disable_mdi(); + spin_unlock_irq(&lp->lock); +} +#endif + +/* ......................... ADDRESS MANAGEMENT ........................ */ + +/* + * NOTE: Your bootloader must always set the MAC address correctly before + * booting into Linux. + * + * - It must always set the MAC address after reset, even if it doesn't + * happen to access the Ethernet while it's booting. Some versions of + * U-Boot on the AT91RM9200-DK do not do this. + * + * - Likewise it must store the addresses in the correct byte order. + * MicroMonitor (uMon) on the CSB337 does this incorrectly (and + * continues to do so, for bug-compatibility). + */ + +static short __init unpack_mac_address(struct net_device *dev, unsigned int hi, unsigned int lo) +{ + char addr[6]; + + if (machine_is_csb337()) { + addr[5] = (lo & 0xff); /* The CSB337 bootloader stores the MAC the wrong-way around */ + addr[4] = (lo & 0xff00) >> 8; + addr[3] = (lo & 0xff0000) >> 16; + addr[2] = (lo & 0xff000000) >> 24; + addr[1] = (hi & 0xff); + addr[0] = (hi & 0xff00) >> 8; + } + else { + addr[0] = (lo & 0xff); + addr[1] = (lo & 0xff00) >> 8; + addr[2] = (lo & 0xff0000) >> 16; + addr[3] = (lo & 0xff000000) >> 24; + addr[4] = (hi & 0xff); + addr[5] = (hi & 0xff00) >> 8; + } + + if (is_valid_ether_addr(addr)) { + memcpy(dev->dev_addr, &addr, 6); + return 1; + } + return 0; +} + +/* + * Set the ethernet MAC address in dev->dev_addr + */ +static void __init get_mac_address(struct net_device *dev) +{ + /* Check Specific-Address 1 */ + if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA1H), at91_emac_read(AT91_EMAC_SA1L))) + return; + /* Check Specific-Address 2 */ + if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA2H), at91_emac_read(AT91_EMAC_SA2L))) + return; + /* Check Specific-Address 3 */ + if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA3H), at91_emac_read(AT91_EMAC_SA3L))) + return; + /* Check Specific-Address 4 */ + if (unpack_mac_address(dev, at91_emac_read(AT91_EMAC_SA4H), at91_emac_read(AT91_EMAC_SA4L))) + return; + + printk(KERN_ERR "at91_ether: Your bootloader did not configure a MAC address.\n"); +} + +/* + * Program the hardware MAC address from dev->dev_addr. + */ +static void update_mac_address(struct net_device *dev) +{ + at91_emac_write(AT91_EMAC_SA1L, (dev->dev_addr[3] << 24) | (dev->dev_addr[2] << 16) | (dev->dev_addr[1] << 8) | (dev->dev_addr[0])); + at91_emac_write(AT91_EMAC_SA1H, (dev->dev_addr[5] << 8) | (dev->dev_addr[4])); + + at91_emac_write(AT91_EMAC_SA2L, 0); + at91_emac_write(AT91_EMAC_SA2H, 0); +} + +/* + * Store the new hardware address in dev->dev_addr, and update the MAC. + */ +static int set_mac_address(struct net_device *dev, void* addr) +{ + struct sockaddr *address = addr; + + if (!is_valid_ether_addr(address->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(dev->dev_addr, address->sa_data, dev->addr_len); + update_mac_address(dev); + + printk("%s: Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + return 0; +} + +static int inline hash_bit_value(int bitnr, __u8 *addr) +{ + if (addr[bitnr / 8] & (1 << (bitnr % 8))) + return 1; + return 0; +} + +/* + * The hash address register is 64 bits long and takes up two locations in the memory map. + * The least significant bits are stored in EMAC_HSL and the most significant + * bits in EMAC_HSH. + * + * The unicast hash enable and the multicast hash enable bits in the network configuration + * register enable the reception of hash matched frames. The destination address is + * reduced to a 6 bit index into the 64 bit hash register using the following hash function. + * The hash function is an exclusive or of every sixth bit of the destination address. + * hash_index[5] = da[5] ^ da[11] ^ da[17] ^ da[23] ^ da[29] ^ da[35] ^ da[41] ^ da[47] + * hash_index[4] = da[4] ^ da[10] ^ da[16] ^ da[22] ^ da[28] ^ da[34] ^ da[40] ^ da[46] + * hash_index[3] = da[3] ^ da[09] ^ da[15] ^ da[21] ^ da[27] ^ da[33] ^ da[39] ^ da[45] + * hash_index[2] = da[2] ^ da[08] ^ da[14] ^ da[20] ^ da[26] ^ da[32] ^ da[38] ^ da[44] + * hash_index[1] = da[1] ^ da[07] ^ da[13] ^ da[19] ^ da[25] ^ da[31] ^ da[37] ^ da[43] + * hash_index[0] = da[0] ^ da[06] ^ da[12] ^ da[18] ^ da[24] ^ da[30] ^ da[36] ^ da[42] + * da[0] represents the least significant bit of the first byte received, that is, the multicast/ + * unicast indicator, and da[47] represents the most significant bit of the last byte + * received. + * If the hash index points to a bit that is set in the hash register then the frame will be + * matched according to whether the frame is multicast or unicast. + * A multicast match will be signalled if the multicast hash enable bit is set, da[0] is 1 and + * the hash index points to a bit set in the hash register. + * A unicast match will be signalled if the unicast hash enable bit is set, da[0] is 0 and the + * hash index points to a bit set in the hash register. + * To receive all multicast frames, the hash register should be set with all ones and the + * multicast hash enable bit should be set in the network configuration register. + */ + +/* + * Return the hash index value for the specified address. + */ +static int hash_get_index(__u8 *addr) +{ + int i, j, bitval; + int hash_index = 0; + + for (j = 0; j < 6; j++) { + for (i = 0, bitval = 0; i < 8; i++) + bitval ^= hash_bit_value(i*6 + j, addr); + + hash_index |= (bitval << j); + } + + return hash_index; +} + +/* + * Add multicast addresses to the internal multicast-hash table. + */ +static void at91ether_sethashtable(struct net_device *dev) +{ + struct dev_mc_list *curr; + unsigned long mc_filter[2]; + unsigned int i, bitnr; + + mc_filter[0] = mc_filter[1] = 0; + + curr = dev->mc_list; + for (i = 0; i < dev->mc_count; i++, curr = curr->next) { + if (!curr) break; /* unexpected end of list */ + + bitnr = hash_get_index(curr->dmi_addr); + mc_filter[bitnr >> 5] |= 1 << (bitnr & 31); + } + + at91_emac_write(AT91_EMAC_HSH, mc_filter[0]); + at91_emac_write(AT91_EMAC_HSL, mc_filter[1]); +} + +/* + * Enable/Disable promiscuous and multicast modes. + */ +static void at91ether_set_rx_mode(struct net_device *dev) +{ + unsigned long cfg; + + cfg = at91_emac_read(AT91_EMAC_CFG); + + if (dev->flags & IFF_PROMISC) /* Enable promiscuous mode */ + cfg |= AT91_EMAC_CAF; + else if (dev->flags & (~IFF_PROMISC)) /* Disable promiscuous mode */ + cfg &= ~AT91_EMAC_CAF; + + if (dev->flags & IFF_ALLMULTI) { /* Enable all multicast mode */ + at91_emac_write(AT91_EMAC_HSH, -1); + at91_emac_write(AT91_EMAC_HSL, -1); + cfg |= AT91_EMAC_MTI; + } else if (dev->mc_count > 0) { /* Enable specific multicasts */ + at91ether_sethashtable(dev); + cfg |= AT91_EMAC_MTI; + } else if (dev->flags & (~IFF_ALLMULTI)) { /* Disable all multicast mode */ + at91_emac_write(AT91_EMAC_HSH, 0); + at91_emac_write(AT91_EMAC_HSL, 0); + cfg &= ~AT91_EMAC_MTI; + } + + at91_emac_write(AT91_EMAC_CFG, cfg); +} + + +/* ......................... ETHTOOL SUPPORT ........................... */ + + +static int mdio_read(struct net_device *dev, int phy_id, int location) +{ + unsigned int value; + + read_phy(phy_id, location, &value); + return value; +} + +static void mdio_write(struct net_device *dev, int phy_id, int location, int value) +{ + write_phy(phy_id, location, value); +} + +static int at91ether_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct at91_private *lp = (struct at91_private *) dev->priv; + int ret; + + spin_lock_irq(&lp->lock); + enable_mdi(); + + ret = mii_ethtool_gset(&lp->mii, cmd); + + disable_mdi(); + spin_unlock_irq(&lp->lock); + + if (lp->phy_media == PORT_FIBRE) { /* override media type since mii.c doesn't know */ + cmd->supported = SUPPORTED_FIBRE; + cmd->port = PORT_FIBRE; + } + + return ret; +} + +static int at91ether_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct at91_private *lp = (struct at91_private *) dev->priv; + int ret; + + spin_lock_irq(&lp->lock); + enable_mdi(); + + ret = mii_ethtool_sset(&lp->mii, cmd); + + disable_mdi(); + spin_unlock_irq(&lp->lock); + + return ret; +} + +static int at91ether_nwayreset(struct net_device *dev) +{ + struct at91_private *lp = (struct at91_private *) dev->priv; + int ret; + + spin_lock_irq(&lp->lock); + enable_mdi(); + + ret = mii_nway_restart(&lp->mii); + + disable_mdi(); + spin_unlock_irq(&lp->lock); + + return ret; +} + +static void at91ether_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); + strlcpy(info->version, DRV_VERSION, sizeof(info->version)); + strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info)); +} + +static struct ethtool_ops at91ether_ethtool_ops = { + .get_settings = at91ether_get_settings, + .set_settings = at91ether_set_settings, + .get_drvinfo = at91ether_get_drvinfo, + .nway_reset = at91ether_nwayreset, + .get_link = ethtool_op_get_link, +}; + + +/* ................................ MAC ................................ */ + +/* + * Initialize and start the Receiver and Transmit subsystems + */ +static void at91ether_start(struct net_device *dev) +{ + struct at91_private *lp = (struct at91_private *) dev->priv; + struct recv_desc_bufs *dlist, *dlist_phys; + int i; + unsigned long ctl; + + dlist = lp->dlist; + dlist_phys = lp->dlist_phys; + + for (i = 0; i < MAX_RX_DESCR; i++) { + dlist->descriptors[i].addr = (unsigned int) &dlist_phys->recv_buf[i][0]; + dlist->descriptors[i].size = 0; + } + + /* Set the Wrap bit on the last descriptor */ + dlist->descriptors[i-1].addr |= EMAC_DESC_WRAP; + + /* Reset buffer index */ + lp->rxBuffIndex = 0; + + /* Program address of descriptor list in Rx Buffer Queue register */ + at91_emac_write(AT91_EMAC_RBQP, (unsigned long) dlist_phys); + + /* Enable Receive and Transmit */ + ctl = at91_emac_read(AT91_EMAC_CTL); + at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE | AT91_EMAC_TE); +} + +/* + * Open the ethernet interface + */ +static int at91ether_open(struct net_device *dev) +{ + struct at91_private *lp = (struct at91_private *) dev->priv; + unsigned long ctl; + + if (!is_valid_ether_addr(dev->dev_addr)) + return -EADDRNOTAVAIL; + + clk_enable(ether_clk); /* Re-enable Peripheral clock */ + + /* Clear internal statistics */ + ctl = at91_emac_read(AT91_EMAC_CTL); + at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_CSR); + + /* Update the MAC address (incase user has changed it) */ + update_mac_address(dev); + + /* Enable PHY interrupt */ + enable_phyirq(dev); + + /* Enable MAC interrupts */ + at91_emac_write(AT91_EMAC_IER, AT91_EMAC_RCOM | AT91_EMAC_RBNA + | AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM + | AT91_EMAC_ROVR | AT91_EMAC_ABT); + + /* Determine current link speed */ + spin_lock_irq(&lp->lock); + enable_mdi(); + update_linkspeed(dev); + disable_mdi(); + spin_unlock_irq(&lp->lock); + + at91ether_start(dev); + netif_start_queue(dev); + return 0; +} + +/* + * Close the interface + */ +static int at91ether_close(struct net_device *dev) +{ + unsigned long ctl; + + /* Disable Receiver and Transmitter */ + ctl = at91_emac_read(AT91_EMAC_CTL); + at91_emac_write(AT91_EMAC_CTL, ctl & ~(AT91_EMAC_TE | AT91_EMAC_RE)); + + /* Disable PHY interrupt */ + disable_phyirq(dev); + + /* Disable MAC interrupts */ + at91_emac_write(AT91_EMAC_IDR, AT91_EMAC_RCOM | AT91_EMAC_RBNA + | AT91_EMAC_TUND | AT91_EMAC_RTRY | AT91_EMAC_TCOM + | AT91_EMAC_ROVR | AT91_EMAC_ABT); + + netif_stop_queue(dev); + + clk_disable(ether_clk); /* Disable Peripheral clock */ + + return 0; +} + +/* + * Transmit packet. + */ +static int at91ether_tx(struct sk_buff *skb, struct net_device *dev) +{ + struct at91_private *lp = (struct at91_private *) dev->priv; + + if (at91_emac_read(AT91_EMAC_TSR) & AT91_EMAC_TSR_BNQ) { + netif_stop_queue(dev); + + /* Store packet information (to free when Tx completed) */ + lp->skb = skb; + lp->skb_length = skb->len; + lp->skb_physaddr = dma_map_single(NULL, skb->data, skb->len, DMA_TO_DEVICE); + lp->stats.tx_bytes += skb->len; + + /* Set address of the data in the Transmit Address register */ + at91_emac_write(AT91_EMAC_TAR, lp->skb_physaddr); + /* Set length of the packet in the Transmit Control register */ + at91_emac_write(AT91_EMAC_TCR, skb->len); + + dev->trans_start = jiffies; + } else { + printk(KERN_ERR "at91_ether.c: at91ether_tx() called, but device is busy!\n"); + return 1; /* if we return anything but zero, dev.c:1055 calls kfree_skb(skb) + on this skb, he also reports -ENETDOWN and printk's, so either + we free and return(0) or don't free and return 1 */ + } + + return 0; +} + +/* + * Update the current statistics from the internal statistics registers. + */ +static struct net_device_stats *at91ether_stats(struct net_device *dev) +{ + struct at91_private *lp = (struct at91_private *) dev->priv; + int ale, lenerr, seqe, lcol, ecol; + + if (netif_running(dev)) { + lp->stats.rx_packets += at91_emac_read(AT91_EMAC_OK); /* Good frames received */ + ale = at91_emac_read(AT91_EMAC_ALE); + lp->stats.rx_frame_errors += ale; /* Alignment errors */ + lenerr = at91_emac_read(AT91_EMAC_ELR) + at91_emac_read(AT91_EMAC_USF); + lp->stats.rx_length_errors += lenerr; /* Excessive Length or Undersize Frame error */ + seqe = at91_emac_read(AT91_EMAC_SEQE); + lp->stats.rx_crc_errors += seqe; /* CRC error */ + lp->stats.rx_fifo_errors += at91_emac_read(AT91_EMAC_DRFC); /* Receive buffer not available */ + lp->stats.rx_errors += (ale + lenerr + seqe + + at91_emac_read(AT91_EMAC_CDE) + at91_emac_read(AT91_EMAC_RJB)); + + lp->stats.tx_packets += at91_emac_read(AT91_EMAC_FRA); /* Frames successfully transmitted */ + lp->stats.tx_fifo_errors += at91_emac_read(AT91_EMAC_TUE); /* Transmit FIFO underruns */ + lp->stats.tx_carrier_errors += at91_emac_read(AT91_EMAC_CSE); /* Carrier Sense errors */ + lp->stats.tx_heartbeat_errors += at91_emac_read(AT91_EMAC_SQEE);/* Heartbeat error */ + + lcol = at91_emac_read(AT91_EMAC_LCOL); + ecol = at91_emac_read(AT91_EMAC_ECOL); + lp->stats.tx_window_errors += lcol; /* Late collisions */ + lp->stats.tx_aborted_errors += ecol; /* 16 collisions */ + + lp->stats.collisions += (at91_emac_read(AT91_EMAC_SCOL) + at91_emac_read(AT91_EMAC_MCOL) + lcol + ecol); + } + return &lp->stats; +} + +/* + * Extract received frame from buffer descriptors and sent to upper layers. + * (Called from interrupt context) + */ +static void at91ether_rx(struct net_device *dev) +{ + struct at91_private *lp = (struct at91_private *) dev->priv; + struct recv_desc_bufs *dlist; + unsigned char *p_recv; + struct sk_buff *skb; + unsigned int pktlen; + + dlist = lp->dlist; + while (dlist->descriptors[lp->rxBuffIndex].addr & EMAC_DESC_DONE) { + p_recv = dlist->recv_buf[lp->rxBuffIndex]; + pktlen = dlist->descriptors[lp->rxBuffIndex].size & 0x7ff; /* Length of frame including FCS */ + skb = alloc_skb(pktlen + 2, GFP_ATOMIC); + if (skb != NULL) { + skb_reserve(skb, 2); + memcpy(skb_put(skb, pktlen), p_recv, pktlen); + + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + skb->len = pktlen; + dev->last_rx = jiffies; + lp->stats.rx_bytes += pktlen; + netif_rx(skb); + } + else { + lp->stats.rx_dropped += 1; + printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); + } + + if (dlist->descriptors[lp->rxBuffIndex].size & EMAC_MULTICAST) + lp->stats.multicast++; + + dlist->descriptors[lp->rxBuffIndex].addr &= ~EMAC_DESC_DONE; /* reset ownership bit */ + if (lp->rxBuffIndex == MAX_RX_DESCR-1) /* wrap after last buffer */ + lp->rxBuffIndex = 0; + else + lp->rxBuffIndex++; + } +} + +/* + * MAC interrupt handler + */ +static irqreturn_t at91ether_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct at91_private *lp = (struct at91_private *) dev->priv; + unsigned long intstatus, ctl; + + /* MAC Interrupt Status register indicates what interrupts are pending. + It is automatically cleared once read. */ + intstatus = at91_emac_read(AT91_EMAC_ISR); + + if (intstatus & AT91_EMAC_RCOM) /* Receive complete */ + at91ether_rx(dev); + + if (intstatus & AT91_EMAC_TCOM) { /* Transmit complete */ + /* The TCOM bit is set even if the transmission failed. */ + if (intstatus & (AT91_EMAC_TUND | AT91_EMAC_RTRY)) + lp->stats.tx_errors += 1; + + if (lp->skb) { + dev_kfree_skb_irq(lp->skb); + lp->skb = NULL; + dma_unmap_single(NULL, lp->skb_physaddr, lp->skb_length, DMA_TO_DEVICE); + } + netif_wake_queue(dev); + } + + /* Work-around for Errata #11 */ + if (intstatus & AT91_EMAC_RBNA) { + ctl = at91_emac_read(AT91_EMAC_CTL); + at91_emac_write(AT91_EMAC_CTL, ctl & ~AT91_EMAC_RE); + at91_emac_write(AT91_EMAC_CTL, ctl | AT91_EMAC_RE); + } + + if (intstatus & AT91_EMAC_ROVR) + printk("%s: ROVR error\n", dev->name); + + return IRQ_HANDLED; +} + +/* + * Initialize the ethernet interface + */ +static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_address, struct platform_device *pdev) +{ + struct at91_eth_data *board_data = pdev->dev.platform_data; + struct net_device *dev; + struct at91_private *lp; + unsigned int val; + int res; + + if (at91_dev) /* already initialized */ + return 0; + + dev = alloc_etherdev(sizeof(struct at91_private)); + if (!dev) + return -ENOMEM; + + dev->base_addr = AT91_VA_BASE_EMAC; + dev->irq = AT91_ID_EMAC; + SET_MODULE_OWNER(dev); + + /* Install the interrupt handler */ + if (request_irq(dev->irq, at91ether_interrupt, 0, dev->name, dev)) { + free_netdev(dev); + return -EBUSY; + } + + /* Allocate memory for DMA Receive descriptors */ + lp = (struct at91_private *)dev->priv; + lp->dlist = (struct recv_desc_bufs *) dma_alloc_coherent(NULL, sizeof(struct recv_desc_bufs), (dma_addr_t *) &lp->dlist_phys, GFP_KERNEL); + if (lp->dlist == NULL) { + free_irq(dev->irq, dev); + free_netdev(dev); + return -ENOMEM; + } + lp->board_data = *board_data; + platform_set_drvdata(pdev, dev); + + spin_lock_init(&lp->lock); + + ether_setup(dev); + dev->open = at91ether_open; + dev->stop = at91ether_close; + dev->hard_start_xmit = at91ether_tx; + dev->get_stats = at91ether_stats; + dev->set_multicast_list = at91ether_set_rx_mode; + dev->set_mac_address = set_mac_address; + dev->ethtool_ops = &at91ether_ethtool_ops; + + SET_NETDEV_DEV(dev, &pdev->dev); + + get_mac_address(dev); /* Get ethernet address and store it in dev->dev_addr */ + update_mac_address(dev); /* Program ethernet address into MAC */ + + at91_emac_write(AT91_EMAC_CTL, 0); + + if (lp->board_data.is_rmii) + at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG | AT91_EMAC_RMII); + else + at91_emac_write(AT91_EMAC_CFG, AT91_EMAC_CLK_DIV32 | AT91_EMAC_BIG); + + /* Perform PHY-specific initialization */ + spin_lock_irq(&lp->lock); + enable_mdi(); + if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) { + read_phy(phy_address, MII_DSCR_REG, &val); + if ((val & (1 << 10)) == 0) /* DSCR bit 10 is 0 -- fiber mode */ + lp->phy_media = PORT_FIBRE; + } else if (machine_is_csb337()) { + /* mix link activity status into LED2 link state */ + write_phy(phy_address, MII_LEDCTRL_REG, 0x0d22); + } + disable_mdi(); + spin_unlock_irq(&lp->lock); + + lp->mii.dev = dev; /* Support for ethtool */ + lp->mii.mdio_read = mdio_read; + lp->mii.mdio_write = mdio_write; + + lp->phy_type = phy_type; /* Type of PHY connected */ + lp->phy_address = phy_address; /* MDI address of PHY */ + + /* Register the network interface */ + res = register_netdev(dev); + if (res) { + free_irq(dev->irq, dev); + free_netdev(dev); + dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys); + return res; + } + at91_dev = dev; + + /* Determine current link speed */ + spin_lock_irq(&lp->lock); + enable_mdi(); + update_linkspeed(dev); + disable_mdi(); + spin_unlock_irq(&lp->lock); + netif_carrier_off(dev); /* will be enabled in open() */ + + /* Display ethernet banner */ + printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%02x:%02x:%02x:%02x:%02x:%02x)\n", + dev->name, (uint) dev->base_addr, dev->irq, + at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-", + at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex", + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) + printk(KERN_INFO "%s: Davicom 9196 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)"); + else if (phy_type == MII_LXT971A_ID) + printk(KERN_INFO "%s: Intel LXT971A PHY\n", dev->name); + else if (phy_type == MII_RTL8201_ID) + printk(KERN_INFO "%s: Realtek RTL8201(B)L PHY\n", dev->name); + else if (phy_type == MII_BCM5221_ID) + printk(KERN_INFO "%s: Broadcom BCM5221 PHY\n", dev->name); + else if (phy_type == MII_DP83847_ID) + printk(KERN_INFO "%s: National Semiconductor DP83847 PHY\n", dev->name); + else if (phy_type == MII_AC101L_ID) + printk(KERN_INFO "%s: Altima AC101L PHY\n", dev->name); + else if (phy_type == MII_KS8721_ID) + printk(KERN_INFO "%s: Micrel KS8721 PHY\n", dev->name); + + return 0; +} + +/* + * Detect MAC and PHY and perform initialization + */ +static int __init at91ether_probe(struct platform_device *pdev) +{ + unsigned int phyid1, phyid2; + int detected = -1; + unsigned long phy_id; + unsigned short phy_address = 0; + + ether_clk = clk_get(&pdev->dev, "ether_clk"); + if (!ether_clk) { + printk(KERN_ERR "at91_ether: no clock defined\n"); + return -ENODEV; + } + clk_enable(ether_clk); /* Enable Peripheral clock */ + + while ((detected != 0) && (phy_address < 32)) { + /* Read the PHY ID registers */ + enable_mdi(); + read_phy(phy_address, MII_PHYSID1, &phyid1); + read_phy(phy_address, MII_PHYSID2, &phyid2); + disable_mdi(); + + phy_id = (phyid1 << 16) | (phyid2 & 0xfff0); + switch (phy_id) { + case MII_DM9161_ID: /* Davicom 9161: PHY_ID1 = 0x181, PHY_ID2 = B881 */ + case MII_DM9161A_ID: /* Davicom 9161A: PHY_ID1 = 0x181, PHY_ID2 = B8A0 */ + case MII_LXT971A_ID: /* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */ + case MII_RTL8201_ID: /* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */ + case MII_BCM5221_ID: /* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */ + case MII_DP83847_ID: /* National Semiconductor DP83847: */ + case MII_AC101L_ID: /* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */ + case MII_KS8721_ID: /* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */ + detected = at91ether_setup(phy_id, phy_address, pdev); + break; + } + + phy_address++; + } + + clk_disable(ether_clk); /* Disable Peripheral clock */ + + return detected; +} + +static int __devexit at91ether_remove(struct platform_device *pdev) +{ + struct at91_private *lp = (struct at91_private *) at91_dev->priv; + + unregister_netdev(at91_dev); + free_irq(at91_dev->irq, at91_dev); + dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys); + clk_put(ether_clk); + + free_netdev(at91_dev); + at91_dev = NULL; + return 0; +} + +static struct platform_driver at91ether_driver = { + .probe = at91ether_probe, + .remove = __devexit_p(at91ether_remove), + /* FIXME: support suspend and resume */ + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, +}; + +static int __init at91ether_init(void) +{ + return platform_driver_register(&at91ether_driver); +} + +static void __exit at91ether_exit(void) +{ + platform_driver_unregister(&at91ether_driver); +} + +module_init(at91ether_init) +module_exit(at91ether_exit) + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AT91RM9200 EMAC Ethernet driver"); +MODULE_AUTHOR("Andrew Victor"); diff --git a/drivers/net/arm/at91_ether.h b/drivers/net/arm/at91_ether.h new file mode 100644 index 00000000000..9885735c9c8 --- /dev/null +++ b/drivers/net/arm/at91_ether.h @@ -0,0 +1,101 @@ +/* + * Ethernet driver for the Atmel AT91RM9200 (Thunder) + * + * Copyright (C) SAN People (Pty) Ltd + * + * Based on an earlier Atmel EMAC macrocell driver by Atmel and Lineo Inc. + * Initial version by Rick Bronson. + * + * 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. + */ + +#ifndef AT91_ETHERNET +#define AT91_ETHERNET + + +/* Davicom 9161 PHY */ +#define MII_DM9161_ID 0x0181b880 +#define MII_DM9161A_ID 0x0181b8a0 + +/* Davicom specific registers */ +#define MII_DSCR_REG 16 +#define MII_DSCSR_REG 17 +#define MII_DSINTR_REG 21 + +/* Intel LXT971A PHY */ +#define MII_LXT971A_ID 0x001378E0 + +/* Intel specific registers */ +#define MII_ISINTE_REG 18 +#define MII_ISINTS_REG 19 +#define MII_LEDCTRL_REG 20 + +/* Realtek RTL8201 PHY */ +#define MII_RTL8201_ID 0x00008200 + +/* Broadcom BCM5221 PHY */ +#define MII_BCM5221_ID 0x004061e0 + +/* Broadcom specific registers */ +#define MII_BCMINTR_REG 26 + +/* National Semiconductor DP83847 */ +#define MII_DP83847_ID 0x20005c30 + +/* Altima AC101L PHY */ +#define MII_AC101L_ID 0x00225520 + +/* Micrel KS8721 PHY */ +#define MII_KS8721_ID 0x00221610 + +/* ........................................................................ */ + +#define MAX_RBUFF_SZ 0x600 /* 1518 rounded up */ +#define MAX_RX_DESCR 9 /* max number of receive buffers */ + +#define EMAC_DESC_DONE 0x00000001 /* bit for if DMA is done */ +#define EMAC_DESC_WRAP 0x00000002 /* bit for wrap */ + +#define EMAC_BROADCAST 0x80000000 /* broadcast address */ +#define EMAC_MULTICAST 0x40000000 /* multicast address */ +#define EMAC_UNICAST 0x20000000 /* unicast address */ + +struct rbf_t +{ + unsigned int addr; + unsigned long size; +}; + +struct recv_desc_bufs +{ + struct rbf_t descriptors[MAX_RX_DESCR]; /* must be on sizeof (rbf_t) boundary */ + char recv_buf[MAX_RX_DESCR][MAX_RBUFF_SZ]; /* must be on long boundary */ +}; + +struct at91_private +{ + struct net_device_stats stats; + struct mii_if_info mii; /* ethtool support */ + struct at91_eth_data board_data; /* board-specific configuration */ + + /* PHY */ + unsigned long phy_type; /* type of PHY (PHY_ID) */ + spinlock_t lock; /* lock for MDI interface */ + short phy_media; /* media interface type */ + unsigned short phy_address; /* 5-bit MDI address of PHY (0..31) */ + + /* Transmit */ + struct sk_buff *skb; /* holds skb until xmit interrupt completes */ + dma_addr_t skb_physaddr; /* phys addr from pci_map_single */ + int skb_length; /* saved skb length for pci_unmap_single */ + + /* Receive */ + int rxBuffIndex; /* index into receive descriptor list */ + struct recv_desc_bufs *dlist; /* descriptor list address */ + struct recv_desc_bufs *dlist_phys; /* descriptor list physical address */ +}; + +#endif -- cgit v1.2.3 From b2fd16b4ff2508ac16ae994f4bcd941f97754c00 Mon Sep 17 00:00:00 2001 From: Horms Date: Thu, 23 Mar 2006 16:36:28 +0900 Subject: [PATCH] net: ne2k.c won't compile if pci_clone_list is const net: ne2k.c won't compile if pci_clone_list is const f71e130966ba429dbd24be08ddbcdf263df9a5ad which (amongst other things) made pci_clone_list in ne2k-pci.c const causes the following compile error. This patch reverses that portion of that changeset drivers/net/ne2k-pci.c:123: error: pci_clone_list causes a section type conflict ~/ gcc --version gcc (GCC) 4.0.3 (Debian 4.0.3-1) ~/ dpkg gcc-4.0 | grep Version Version: 4.0.3-1 Signed-Off-By: Horms --- drivers/net/ne2k-pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index e3ebb5803b0..d11821dd86e 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -117,7 +117,7 @@ enum ne2k_pci_chipsets { }; -static const struct { +static struct { char *name; int flags; } pci_clone_list[] __devinitdata = { -- cgit v1.2.3 From 868d2c1efe9cdd259b67a80d60a7fb2fcecd3d68 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Fri, 24 Mar 2006 15:47:25 -0800 Subject: [WIRELESS]: Fix config dependencies. I accidentally ended up with a config that set NET_RADIO off, and NET_WIRELESS_RTNETLINK on, which blew up thus.. net/built-in.o: In function `do_setlink':net/core/rtnetlink.c:479: undefined reference to `wireless_rtnetlink_set' net/built-in.o: In function `do_getlink':net/core/rtnetlink.c:521: undefined reference to `wireless_rtnetlink_get' Signed-off-by: Dave Jones Signed-off-by: David S. Miller --- drivers/net/wireless/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 6a1033ec06c..fd17aa8491b 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -27,6 +27,7 @@ config NET_RADIO config NET_WIRELESS_RTNETLINK bool "Wireless Extension API over RtNetlink" + depends on NET_RADIO ---help--- Support the Wireless Extension API over the RtNetlink socket in addition to the traditional ioctl interface (selected above). -- cgit v1.2.3 From 8d3b33f67fdc0fb364a1ef6d8fbbea7c2e4e6c98 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sat, 25 Mar 2006 03:07:05 -0800 Subject: [PATCH] Remove MODULE_PARM MODULE_PARM was actually breaking: recent gcc version optimize them out as unused. It's time to replace the last users, which are generally in the most unloved drivers anyway. Signed-off-by: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/atari_bionet.c | 2 +- drivers/net/atari_pamsnet.c | 2 +- drivers/net/atarilance.c | 2 +- drivers/net/cassini.c | 11 ++++++----- drivers/net/chelsio/cxgb2.c | 2 +- drivers/net/fec_8xx/fec_main.c | 4 ++-- drivers/net/fs_enet/fs_enet-main.c | 4 ++-- drivers/net/gt96100eth.c | 4 ++-- drivers/net/hamradio/dmascc.c | 2 +- drivers/net/hamradio/mkiss.c | 2 +- drivers/net/irda/irport.c | 4 ++-- drivers/net/lasi_82596.c | 6 +++--- drivers/net/mac89x0.c | 2 +- drivers/net/mace.c | 2 +- drivers/net/meth.c | 2 +- drivers/net/ne-h8300.c | 6 +++--- drivers/net/ni5010.c | 4 ++-- drivers/net/sun3lance.c | 2 +- 18 files changed, 32 insertions(+), 31 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c index 0095384ff45..5e5f80b99b9 100644 --- a/drivers/net/atari_bionet.c +++ b/drivers/net/atari_bionet.c @@ -123,7 +123,7 @@ static char version[] = * Global variable 'bionet_debug'. Can be set at load time by 'insmod' */ unsigned int bionet_debug = NET_DEBUG; -MODULE_PARM(bionet_debug, "i"); +module_param(bionet_debug, int, 0); MODULE_PARM_DESC(bionet_debug, "bionet debug level (0-2)"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c index 8b997809f9d..d6039e62d83 100644 --- a/drivers/net/atari_pamsnet.c +++ b/drivers/net/atari_pamsnet.c @@ -119,7 +119,7 @@ static char *version = * Global variable 'pamsnet_debug'. Can be set at load time by 'insmod' */ unsigned int pamsnet_debug = NET_DEBUG; -MODULE_PARM(pamsnet_debug, "i"); +module_param(pamsnet_debug, int, 0); MODULE_PARM_DESC(pamsnet_debug, "pamsnet debug enable (0-1)"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index e01b6a78ec6..442b2cbeb58 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -78,7 +78,7 @@ static int lance_debug = LANCE_DEBUG; #else static int lance_debug = 1; #endif -MODULE_PARM(lance_debug, "i"); +module_param(lance_debug, int, 0); MODULE_PARM_DESC(lance_debug, "atarilance debug level (0-3)"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 8f1573e658a..ac48f754350 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -192,12 +192,15 @@ static char version[] __devinitdata = DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; +static int cassini_debug = -1; /* -1 == use CAS_DEF_MSG_ENABLE as value */ +static int link_mode; + MODULE_AUTHOR("Adrian Sun (asun@darksunrising.com)"); MODULE_DESCRIPTION("Sun Cassini(+) ethernet driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(cassini_debug, "i"); +module_param(cassini_debug, int, 0); MODULE_PARM_DESC(cassini_debug, "Cassini bitmapped debugging message enable value"); -MODULE_PARM(link_mode, "i"); +module_param(link_mode, int, 0); MODULE_PARM_DESC(link_mode, "default link mode"); /* @@ -209,7 +212,7 @@ MODULE_PARM_DESC(link_mode, "default link mode"); * Value in seconds, for user input. */ static int linkdown_timeout = DEFAULT_LINKDOWN_TIMEOUT; -MODULE_PARM(linkdown_timeout, "i"); +module_param(linkdown_timeout, int, 0); MODULE_PARM_DESC(linkdown_timeout, "min reset interval in sec. for PCS linkdown issue; disabled if not positive"); @@ -221,8 +224,6 @@ MODULE_PARM_DESC(linkdown_timeout, static int link_transition_timeout; -static int cassini_debug = -1; /* -1 == use CAS_DEF_MSG_ENABLE as value */ -static int link_mode; static u16 link_modes[] __devinitdata = { BMCR_ANENABLE, /* 0 : autoneg */ diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 349ebe783ed..7fe2638ae06 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -124,7 +124,7 @@ MODULE_LICENSE("GPL"); static int dflt_msg_enable = DFLT_MSG_ENABLE; -MODULE_PARM(dflt_msg_enable, "i"); +module_param(dflt_msg_enable, int, 0); MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T1 message enable bitmap"); diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c index b4f3a9f8a53..7e433809713 100644 --- a/drivers/net/fec_8xx/fec_main.c +++ b/drivers/net/fec_8xx/fec_main.c @@ -55,11 +55,11 @@ MODULE_AUTHOR("Pantelis Antoniou "); MODULE_DESCRIPTION("Motorola 8xx FEC ethernet driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(fec_8xx_debug, "i"); +int fec_8xx_debug = -1; /* -1 == use FEC_8XX_DEF_MSG_ENABLE as value */ +module_param(fec_8xx_debug, int, 0); MODULE_PARM_DESC(fec_8xx_debug, "FEC 8xx bitmapped debugging message enable value"); -int fec_8xx_debug = -1; /* -1 == use FEC_8XX_DEF_MSG_ENABLE as value */ /*************************************************/ diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index f5d49a11065..196298f33db 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -58,11 +58,11 @@ MODULE_DESCRIPTION("Freescale Ethernet Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_MODULE_VERSION); -MODULE_PARM(fs_enet_debug, "i"); +int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ +module_param(fs_enet_debug, int, 0); MODULE_PARM_DESC(fs_enet_debug, "Freescale bitmapped debugging message enable value"); -int fs_enet_debug = -1; /* -1 == use FS_ENET_DEF_MSG_ENABLE as value */ static void fs_set_multicast_list(struct net_device *dev) { diff --git a/drivers/net/gt96100eth.c b/drivers/net/gt96100eth.c index 5958a631472..2d243540461 100644 --- a/drivers/net/gt96100eth.c +++ b/drivers/net/gt96100eth.c @@ -114,8 +114,8 @@ static int max_interrupt_work = 32; static char mac0[18] = "00.02.03.04.05.06"; static char mac1[18] = "00.01.02.03.04.05"; -MODULE_PARM(mac0, "c18"); -MODULE_PARM(mac1, "c18"); +module_param_string(mac0, mac0, 18, 0); +module_param_string(mac1, mac0, 18, 0); MODULE_PARM_DESC(mac0, "MAC address for GT96100 ethernet port 0"); MODULE_PARM_DESC(mac1, "MAC address for GT96100 ethernet port 1"); diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index c8dc40214a0..79a8fbcf5f9 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -280,7 +280,7 @@ static unsigned long rand; MODULE_AUTHOR("Klaus Kudielka"); MODULE_DESCRIPTION("Driver for high-speed SCC boards"); -MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i"); +module_param_array(io, int, NULL, 0); MODULE_LICENSE("GPL"); static void __exit dmascc_exit(void) diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index dc5e9d59dee..d81a8e1eeb8 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -1012,7 +1012,7 @@ static void __exit mkiss_exit_driver(void) MODULE_AUTHOR("Ralf Baechle DL5RB "); MODULE_DESCRIPTION("KISS driver for AX.25 over TTYs"); -MODULE_PARM(crc_force, "i"); +module_param(crc_force, int, 0); MODULE_PARM_DESC(crc_force, "crc [0 = auto | 1 = none | 2 = flexnet | 3 = smack]"); MODULE_LICENSE("GPL"); MODULE_ALIAS_LDISC(N_AX25); diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index 6070195b87b..98fa5319e5c 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -1118,9 +1118,9 @@ static void __exit irport_cleanup(void) } } -MODULE_PARM(io, "1-4i"); +module_param_array(io, int, NULL, 0); MODULE_PARM_DESC(io, "Base I/O addresses"); -MODULE_PARM(irq, "1-4i"); +module_param_array(irq, int, NULL, 0); MODULE_PARM_DESC(irq, "IRQ lines"); MODULE_AUTHOR("Dag Brattli "); diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c index f7b7238d835..957888de3d7 100644 --- a/drivers/net/lasi_82596.c +++ b/drivers/net/lasi_82596.c @@ -177,7 +177,7 @@ static int i596_debug = (DEB_SERIOUS|DEB_PROBE); MODULE_AUTHOR("Richard Hirst"); MODULE_DESCRIPTION("i82596 driver"); MODULE_LICENSE("GPL"); -MODULE_PARM(i596_debug, "i"); +module_param(i596_debug, int, 0); MODULE_PARM_DESC(i596_debug, "lasi_82596 debug mask"); /* Copy frames shorter than rx_copybreak, otherwise pass on up in @@ -1520,9 +1520,9 @@ static void set_multicast_list(struct net_device *dev) } } -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "lasi_82596 debug mask"); static int debug = -1; +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "lasi_82596 debug mask"); static int num_drivers; static struct net_device *netdevs[MAX_DRIVERS]; diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index f65b0db111b..cd3c9a5a98b 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -629,7 +629,7 @@ static int set_mac_address(struct net_device *dev, void *addr) static struct net_device *dev_cs89x0; static int debug; -MODULE_PARM(debug, "i"); +module_param(debug, int, 0); MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 2a5add257b8..77792b28602 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -1042,7 +1042,7 @@ static void __exit mace_cleanup(void) MODULE_AUTHOR("Paul Mackerras"); MODULE_DESCRIPTION("PowerMac MACE driver."); -MODULE_PARM(port_aaui, "i"); +module_param(port_aaui, int, 0); MODULE_PARM_DESC(port_aaui, "MACE uses AAUI port (0-1)"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/meth.c b/drivers/net/meth.c index e23655f5049..d644bf3a933 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -62,7 +62,7 @@ MODULE_DESCRIPTION("SGI O2 Builtin Fast Ethernet driver"); #ifdef HAVE_TX_TIMEOUT static int timeout = TX_TIMEOUT; -MODULE_PARM(timeout, "i"); +module_param(timeout, int, 0); #endif /* diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index aaebd28a192..7ea3d596ac3 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -601,9 +601,9 @@ static int io[MAX_NE_CARDS]; static int irq[MAX_NE_CARDS]; static int bad[MAX_NE_CARDS]; /* 0xbad = bad sig or no reset ack */ -MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); -MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); -MODULE_PARM(bad, "1-" __MODULE_STRING(MAX_NE_CARDS) "i"); +module_param_array(io, int, NULL, 0); +module_param_array(irq, int, NULL, 0); +module_param_array(bad, int, NULL, 0); MODULE_PARM_DESC(io, "I/O base address(es)"); MODULE_PARM_DESC(irq, "IRQ number(s)"); MODULE_DESCRIPTION("H8/300 NE2000 Ethernet driver"); diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 2ab01a5d1d2..a68bf474f6e 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -766,8 +766,8 @@ static void ni5010_show_registers(struct net_device *dev) #ifdef MODULE static struct net_device *dev_ni5010; -MODULE_PARM(io, "i"); -MODULE_PARM(irq, "i"); +module_param(io, int, 0); +module_param(irq, int, 0); MODULE_PARM_DESC(io, "ni5010 I/O base address"); MODULE_PARM_DESC(irq, "ni5010 IRQ number"); diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 01bdb233405..d4c0002b43d 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -71,7 +71,7 @@ static int lance_debug = LANCE_DEBUG; #else static int lance_debug = 1; #endif -MODULE_PARM(lance_debug, "i"); +module_param(lance_debug, int, 0); MODULE_PARM_DESC(lance_debug, "SUN3 Lance debug level (0-3)"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e51c01b08474ea454a965a937fff0407ab6714c7 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sat, 25 Mar 2006 03:07:17 -0800 Subject: [PATCH] hp300: fix driver_register() return handling, remove dio_module_init() Remove the assumption that driver_register() returns the number of devices bound to the driver. In fact, it returns zero for success or a negative error value. dio_module_init() used the device count to automatically unregister and unload drivers that found no devices. That might have worked at one time, but has been broken for some time because dio_register_driver() returned either a negative error or a positive count (never zero). So it could only unregister on failure, when it's not needed anyway. This functionality could be resurrected in individual drivers by counting devices in their .probe() methods. Signed-off-by: Bjorn Helgaas Cc: Philip Blundell Cc: Jochen Friedrich Cc: "Antonino A. Daplas" Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/hplance.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/hplance.c b/drivers/net/hplance.c index d8410634bca..68569346460 100644 --- a/drivers/net/hplance.c +++ b/drivers/net/hplance.c @@ -217,7 +217,7 @@ static int hplance_close(struct net_device *dev) int __init hplance_init_module(void) { - return dio_module_init(&hplance_driver); + return dio_register_driver(&hplance_driver); } void __exit hplance_cleanup_module(void) -- cgit v1.2.3 From c2f6fabb2ed3b869bc254c6cdc73d6beaaaf700f Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sat, 25 Mar 2006 03:07:19 -0800 Subject: [PATCH] EISA: tidy-up driver_register() return value Remove the assumption that driver_register() returns the number of devices bound to the driver. In fact, it returns zero for success or a negative error value. Signed-off-by: Bjorn Helgaas Acked-by: Jeff Garzik Acked-by: Marc Zyngier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/3c59x.c | 20 ++++++++++++-------- drivers/net/dgrs.c | 14 +++++++------- 2 files changed, 19 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 5d11a06ecb2..d339308539f 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1096,14 +1096,18 @@ static int __init vortex_eisa_init (void) int orig_cards_found = vortex_cards_found; #ifdef CONFIG_EISA - if (eisa_driver_register (&vortex_eisa_driver) >= 0) { - /* Because of the way EISA bus is probed, we cannot assume - * any device have been found when we exit from - * eisa_driver_register (the bus root driver may not be - * initialized yet). So we blindly assume something was - * found, and let the sysfs magic happend... */ - - eisa_found = 1; + int err; + + err = eisa_driver_register (&vortex_eisa_driver); + if (!err) { + /* + * Because of the way EISA bus is probed, we cannot assume + * any device have been found when we exit from + * eisa_driver_register (the bus root driver may not be + * initialized yet). So we blindly assume something was + * found, and let the sysfs magic happend... + */ + eisa_found = 1; } #endif diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c index 32d13166c6e..e175d487668 100644 --- a/drivers/net/dgrs.c +++ b/drivers/net/dgrs.c @@ -1551,7 +1551,7 @@ MODULE_PARM_DESC(nicmode, "Digi RightSwitch operating mode (1: switch, 2: multi- static int __init dgrs_init_module (void) { int i; - int cardcount = 0; + int err; /* * Command line variable overrides @@ -1593,13 +1593,13 @@ static int __init dgrs_init_module (void) * Find and configure all the cards */ #ifdef CONFIG_EISA - cardcount = eisa_driver_register(&dgrs_eisa_driver); - if (cardcount < 0) - return cardcount; + err = eisa_driver_register(&dgrs_eisa_driver); + if (err) + return err; #endif - cardcount = pci_register_driver(&dgrs_pci_driver); - if (cardcount) - return cardcount; + err = pci_register_driver(&dgrs_pci_driver); + if (err) + return err; return 0; } -- cgit v1.2.3 From 33d8675ea66e79d21da3ed64ce88dfb2a18bc6a7 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sat, 25 Mar 2006 03:07:20 -0800 Subject: [PATCH] amiga: fix driver_register() return handling, remove zorro_module_init() Remove the assumption that driver_register() returns the number of devices bound to the driver. In fact, it returns zero for success or a negative error value. zorro_module_init() used the device count to automatically unregister and unload drivers that found no devices. That might have worked at one time, but has been broken for some time because zorro_register_driver() returned either a negative error or a positive count (never zero). So it could only unregister on failure, when it's not needed anyway. This functionality could be resurrected in individual drivers by counting devices in their .probe() methods. Signed-off-by: Bjorn Helgaas Cc: Geert Uytterhoeven Cc: Roman Zippel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/a2065.c | 2 +- drivers/net/ariadne.c | 2 +- drivers/net/hydra.c | 2 +- drivers/net/zorro8390.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 8e538a6d7d9..79bb56b8dce 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -829,7 +829,7 @@ static void __devexit a2065_remove_one(struct zorro_dev *z) static int __init a2065_init_module(void) { - return zorro_module_init(&a2065_driver); + return zorro_register_driver(&a2065_driver); } static void __exit a2065_cleanup_module(void) diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 9fe93acfc8e..d1b6b1f794e 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -864,7 +864,7 @@ static void __devexit ariadne_remove_one(struct zorro_dev *z) static int __init ariadne_init_module(void) { - return zorro_module_init(&ariadne_driver); + return zorro_register_driver(&ariadne_driver); } static void __exit ariadne_cleanup_module(void) diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index 6e0ca7340a8..d9fb8e74e63 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -242,7 +242,7 @@ static void __devexit hydra_remove_one(struct zorro_dev *z) static int __init hydra_init_module(void) { - return zorro_module_init(&hydra_driver); + return zorro_register_driver(&hydra_driver); } static void __exit hydra_cleanup_module(void) diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index 76102160359..8037e5806d0 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -426,7 +426,7 @@ static void __devexit zorro8390_remove_one(struct zorro_dev *z) static int __init zorro8390_init_module(void) { - return zorro_module_init(&zorro8390_driver); + return zorro_register_driver(&zorro8390_driver); } static void __exit zorro8390_cleanup_module(void) -- cgit v1.2.3 From 14cc3e2b633bb64063698980974df4535368e98f Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Sun, 26 Mar 2006 01:37:14 -0800 Subject: [PATCH] sem2mutex: misc static one-file mutexes Semaphore to mutex conversion. The conversion was generated via scripts, and the result was validated automatically via a script as well. Signed-off-by: Ingo Molnar Cc: Dave Jones Cc: Paul Mackerras Cc: Ralf Baechle Cc: Jens Axboe Cc: Neil Brown Acked-by: Alasdair G Kergon Cc: Greg KH Cc: Dominik Brodowski Cc: Adam Belay Cc: Martin Schwidefsky Cc: "David S. Miller" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/wan/dscc4.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 1ff5de076d2..4505540e3c5 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -105,6 +105,7 @@ #include #include #include +#include /* Version */ static const char version[] = "$Id: dscc4.c,v 1.173 2003/09/20 23:55:34 romieu Exp $ for Linux\n"; @@ -112,7 +113,7 @@ static int debug; static int quartz; #ifdef CONFIG_DSCC4_PCI_RST -static DECLARE_MUTEX(dscc4_sem); +static DEFINE_MUTEX(dscc4_mutex); static u32 dscc4_pci_config_store[16]; #endif @@ -1018,7 +1019,7 @@ static void dscc4_pci_reset(struct pci_dev *pdev, void __iomem *ioaddr) { int i; - down(&dscc4_sem); + mutex_lock(&dscc4_mutex); for (i = 0; i < 16; i++) pci_read_config_dword(pdev, i << 2, dscc4_pci_config_store + i); @@ -1039,7 +1040,7 @@ static void dscc4_pci_reset(struct pci_dev *pdev, void __iomem *ioaddr) for (i = 0; i < 16; i++) pci_write_config_dword(pdev, i << 2, dscc4_pci_config_store[i]); - up(&dscc4_sem); + mutex_unlock(&dscc4_mutex); } #else #define dscc4_pci_reset(pdev,ioaddr) do {} while (0) -- cgit v1.2.3 From 125d5ce8a4e9e4babaed52518fecc9eb6958455d Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Sun, 26 Mar 2006 01:37:39 -0800 Subject: [PATCH] 3c59x: use mii_check_media Check for media changes and netif_carrier by using mii_check_media() if mii is used. Signed-off-by: Steffen Klassert Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/3c59x.c | 126 ++++++++++++++++++++-------------------------------- 1 file changed, 49 insertions(+), 77 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index d339308539f..4ae78bf377c 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1335,7 +1335,7 @@ static int __devinit vortex_probe1(struct device *gendev, vp->enable_wol = 1; } - vp->force_fd = vp->full_duplex; + vp->mii.force_media = vp->full_duplex; vp->options = option; /* Read the station address from the EEPROM. */ EL3WINDOW(0); @@ -1624,6 +1624,46 @@ issue_and_wait(struct net_device *dev, int cmd) dev->name, cmd, ioread16(ioaddr + EL3_STATUS)); } +static void +vortex_set_duplex(struct net_device *dev) +{ + struct vortex_private *vp = netdev_priv(dev); + void __iomem *ioaddr = vp->ioaddr; + + printk(KERN_INFO "%s: setting %s-duplex.\n", + dev->name, (vp->full_duplex) ? "full" : "half"); + + EL3WINDOW(3); + /* Set the full-duplex bit. */ + iowrite16(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | + (vp->large_frames ? 0x40 : 0) | + ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? + 0x100 : 0), + ioaddr + Wn3_MAC_Ctrl); + + issue_and_wait(dev, TxReset); + /* + * Don't reset the PHY - that upsets autonegotiation during DHCP operations. + */ + issue_and_wait(dev, RxReset|0x04); +} + +static void vortex_check_media(struct net_device *dev, unsigned int init) +{ + struct vortex_private *vp = netdev_priv(dev); + unsigned int ok_to_print = 0; + + if (vortex_debug > 3) + ok_to_print = 1; + + if (mii_check_media(&vp->mii, ok_to_print, init)) { + vp->full_duplex = vp->mii.full_duplex; + vortex_set_duplex(dev); + } else if (init) { + vortex_set_duplex(dev); + } +} + static void vortex_up(struct net_device *dev) { @@ -1684,53 +1724,20 @@ vortex_up(struct net_device *dev) printk(KERN_DEBUG "%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name); - vp->full_duplex = vp->force_fd; + vp->full_duplex = vp->mii.force_media; config = BFINS(config, dev->if_port, 20, 4); if (vortex_debug > 6) printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config); iowrite32(config, ioaddr + Wn3_Config); + netif_carrier_off(dev); if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { - int mii_reg1, mii_reg5; EL3WINDOW(4); - /* Read BMSR (reg1) only to clear old status. */ - mii_reg1 = mdio_read(dev, vp->phys[0], MII_BMSR); - mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA); - if (mii_reg5 == 0xffff || mii_reg5 == 0x0000) { - netif_carrier_off(dev); /* No MII device or no link partner report */ - } else { - mii_reg5 &= vp->advertising; - if ((mii_reg5 & 0x0100) != 0 /* 100baseTx-FD */ - || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */ - vp->full_duplex = 1; - netif_carrier_on(dev); - } - vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0); - if (vortex_debug > 1) - printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x," - " info1 %04x, setting %s-duplex.\n", - dev->name, vp->phys[0], - mii_reg1, mii_reg5, - vp->info1, ((vp->info1 & 0x8000) || vp->full_duplex) ? "full" : "half"); - EL3WINDOW(3); + vortex_check_media(dev, 1); } + else + vortex_set_duplex(dev); - /* Set the full-duplex bit. */ - iowrite16( ((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) | - (vp->large_frames ? 0x40 : 0) | - ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), - ioaddr + Wn3_MAC_Ctrl); - - if (vortex_debug > 1) { - printk(KERN_DEBUG "%s: vortex_up() InternalConfig %8.8x.\n", - dev->name, config); - } - - issue_and_wait(dev, TxReset); - /* - * Don't reset the PHY - that upsets autonegotiation during DHCP operations. - */ - issue_and_wait(dev, RxReset|0x04); iowrite16(SetStatusEnb | 0x00, ioaddr + EL3_CMD); @@ -1892,7 +1899,7 @@ vortex_timer(unsigned long data) void __iomem *ioaddr = vp->ioaddr; int next_tick = 60*HZ; int ok = 0; - int media_status, mii_status, old_window; + int media_status, old_window; if (vortex_debug > 2) { printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n", @@ -1924,44 +1931,9 @@ vortex_timer(unsigned long data) break; case XCVR_MII: case XCVR_NWAY: { - spin_lock_bh(&vp->lock); - mii_status = mdio_read(dev, vp->phys[0], MII_BMSR); - if (!(mii_status & BMSR_LSTATUS)) { - /* Re-read to get actual link status */ - mii_status = mdio_read(dev, vp->phys[0], MII_BMSR); - } ok = 1; - if (vortex_debug > 2) - printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n", - dev->name, mii_status); - if (mii_status & BMSR_LSTATUS) { - int mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA); - if (! vp->force_fd && mii_reg5 != 0xffff) { - int duplex; - - mii_reg5 &= vp->advertising; - duplex = (mii_reg5&0x0100) || (mii_reg5 & 0x01C0) == 0x0040; - if (vp->full_duplex != duplex) { - vp->full_duplex = duplex; - printk(KERN_INFO "%s: Setting %s-duplex based on MII " - "#%d link partner capability of %4.4x.\n", - dev->name, vp->full_duplex ? "full" : "half", - vp->phys[0], mii_reg5); - /* Set the full-duplex bit. */ - EL3WINDOW(3); - iowrite16( (vp->full_duplex ? 0x20 : 0) | - (vp->large_frames ? 0x40 : 0) | - ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), - ioaddr + Wn3_MAC_Ctrl); - if (vortex_debug > 1) - printk(KERN_DEBUG "Setting duplex in Wn3_MAC_Ctrl\n"); - /* AKPM: bug: should reset Tx and Rx after setting Duplex. Page 180 */ - } - } - netif_carrier_on(dev); - } else { - netif_carrier_off(dev); - } + spin_lock_bh(&vp->lock); + vortex_check_media(dev, 0); spin_unlock_bh(&vp->lock); } break; -- cgit v1.2.3 From b4ff6450f5336c492d1e2f184d3b8186e0716b7a Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Sun, 26 Mar 2006 01:37:40 -0800 Subject: [PATCH] 3c59x: decrease polling interval Set the polling interval for media changes to 5 seconds if link is down and 60 seconds if link is up. Signed-off-by: Steffen Klassert Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/3c59x.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 4ae78bf377c..3343cbda419 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1943,6 +1943,10 @@ vortex_timer(unsigned long data) dev->name, media_tbl[dev->if_port].name, media_status); ok = 1; } + + if (!netif_carrier_ok(dev)) + next_tick = 5*HZ; + if ( ! ok) { unsigned int config; -- cgit v1.2.3 From e94d10eb0d77ae70378f9218631a7be91e0aecff Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Sun, 26 Mar 2006 01:37:41 -0800 Subject: [PATCH] 3c59x: carriercheck for forced media Handle netif_carrier_{on,of} also if media is forced to 10baseT/100baseTx. Signed-off-by: Steffen Klassert Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/3c59x.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 3343cbda419..4655662453b 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -1907,8 +1907,6 @@ vortex_timer(unsigned long data) printk(KERN_DEBUG "dev->watchdog_timeo=%d\n", dev->watchdog_timeo); } - if (vp->medialock) - goto leave_media_alone; disable_irq(dev->irq); old_window = ioread16(ioaddr + EL3_CMD) >> 13; EL3WINDOW(4); @@ -1947,6 +1945,9 @@ vortex_timer(unsigned long data) if (!netif_carrier_ok(dev)) next_tick = 5*HZ; + if (vp->medialock) + goto leave_media_alone; + if ( ! ok) { unsigned int config; @@ -1980,14 +1981,14 @@ vortex_timer(unsigned long data) printk(KERN_DEBUG "wrote 0x%08x to Wn3_Config\n", config); /* AKPM: FIXME: Should reset Rx & Tx here. P60 of 3c90xc.pdf */ } - EL3WINDOW(old_window); - enable_irq(dev->irq); leave_media_alone: if (vortex_debug > 2) printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n", dev->name, media_tbl[dev->if_port].name); + EL3WINDOW(old_window); + enable_irq(dev->irq); mod_timer(&vp->timer, RUN_AT(next_tick)); if (vp->deferred) iowrite16(FakeIntr, ioaddr + EL3_CMD); -- cgit v1.2.3 From 373a688742d7ba31cafc4c7b9bc09eba257860bd Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Sun, 26 Mar 2006 01:37:41 -0800 Subject: [PATCH] 3c59x: use ethtool_op_get_link Use ethtool_op_get_link instead of vortex_get_link. Signed-off-by: Steffen Klassert Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/3c59x.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 4655662453b..1352eb66c74 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -2960,20 +2960,6 @@ static int vortex_nway_reset(struct net_device *dev) return rc; } -static u32 vortex_get_link(struct net_device *dev) -{ - struct vortex_private *vp = netdev_priv(dev); - void __iomem *ioaddr = vp->ioaddr; - unsigned long flags; - int rc; - - spin_lock_irqsave(&vp->lock, flags); - EL3WINDOW(4); - rc = mii_link_ok(&vp->mii); - spin_unlock_irqrestore(&vp->lock, flags); - return rc; -} - static int vortex_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct vortex_private *vp = netdev_priv(dev); @@ -3075,7 +3061,7 @@ static struct ethtool_ops vortex_ethtool_ops = { .get_stats_count = vortex_get_stats_count, .get_settings = vortex_get_settings, .set_settings = vortex_set_settings, - .get_link = vortex_get_link, + .get_link = ethtool_op_get_link, .nway_reset = vortex_nway_reset, .get_perm_addr = ethtool_op_get_perm_addr, }; -- cgit v1.2.3 From 61238602622c965db052927c89901aa08f88d933 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Sun, 26 Mar 2006 01:37:42 -0800 Subject: [PATCH] 3c59x: remove per-driver versioning Remove per-driver versioning. Signed-off-by: Steffen Klassert Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/3c59x.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 1352eb66c74..51ac35966b2 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -196,8 +196,6 @@ #define DRV_NAME "3c59x" -#define DRV_VERSION "LK1.1.19" -#define DRV_RELDATE "10 Nov 2002" @@ -275,10 +273,8 @@ static char version[] __devinitdata = DRV_NAME ": Donald Becker and others. www.scyld.com/network/vortex.html\n"; MODULE_AUTHOR("Donald Becker "); -MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver " - DRV_VERSION " " DRV_RELDATE); +MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver "); MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); /* Operational parameter that usually are not changed. */ @@ -1236,7 +1232,7 @@ static int __devinit vortex_probe1(struct device *gendev, if (print_info) printk (KERN_INFO "See Documentation/networking/vortex.txt\n"); - printk(KERN_INFO "%s: 3Com %s %s at %p. Vers " DRV_VERSION "\n", + printk(KERN_INFO "%s: 3Com %s %s at %p.\n", print_name, pdev ? "PCI" : "EISA", vci->name, @@ -3040,7 +3036,6 @@ static void vortex_get_drvinfo(struct net_device *dev, struct vortex_private *vp = netdev_priv(dev); strcpy(info->driver, DRV_NAME); - strcpy(info->version, DRV_VERSION); if (VORTEX_PCI(vp)) { strcpy(info->bus_info, pci_name(VORTEX_PCI(vp))); } else { -- cgit v1.2.3 From a880c4cd2538293be59121a3658b8de8e3a058e5 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Sun, 26 Mar 2006 01:37:43 -0800 Subject: [PATCH] 3c59x: minor cleanups Remove some whitespaces and codingstyle issues. Signed-off-by: Steffen Klassert Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/3c59x.c | 81 ++++++++++++++++++++++------------------------------- 1 file changed, 34 insertions(+), 47 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 51ac35966b2..70f63891b19 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -900,7 +900,6 @@ static void acpi_set_WOL(struct net_device *dev); static struct ethtool_ops vortex_ethtool_ops; static void set_8021q_mode(struct net_device *dev, int enable); - /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ /* Option count limit only -- unlimited interfaces are supported. */ #define MAX_UNITS 8 @@ -915,8 +914,6 @@ static int global_full_duplex = -1; static int global_enable_wol = -1; static int global_use_mmio = -1; -/* #define dev_alloc_skb dev_alloc_skb_debug */ - /* Variables to work-around the Compaq PCI BIOS32 problem. */ static int compaq_ioaddr, compaq_irq, compaq_device_id = 0x5900; static struct net_device *compaq_net_device; @@ -972,7 +969,7 @@ static void poll_vortex(struct net_device *dev) #ifdef CONFIG_PM -static int vortex_suspend (struct pci_dev *pdev, pm_message_t state) +static int vortex_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); @@ -990,7 +987,7 @@ static int vortex_suspend (struct pci_dev *pdev, pm_message_t state) return 0; } -static int vortex_resume (struct pci_dev *pdev) +static int vortex_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct vortex_private *vp = netdev_priv(dev); @@ -1023,8 +1020,8 @@ static struct eisa_device_id vortex_eisa_ids[] = { { "" } }; -static int vortex_eisa_probe (struct device *device); -static int vortex_eisa_remove (struct device *device); +static int vortex_eisa_probe(struct device *device); +static int vortex_eisa_remove(struct device *device); static struct eisa_driver vortex_eisa_driver = { .id_table = vortex_eisa_ids, @@ -1035,12 +1032,12 @@ static struct eisa_driver vortex_eisa_driver = { } }; -static int vortex_eisa_probe (struct device *device) +static int vortex_eisa_probe(struct device *device) { void __iomem *ioaddr; struct eisa_device *edev; - edev = to_eisa_device (device); + edev = to_eisa_device(device); if (!request_region(edev->base_addr, VORTEX_TOTAL_SIZE, DRV_NAME)) return -EBUSY; @@ -1049,7 +1046,7 @@ static int vortex_eisa_probe (struct device *device) if (vortex_probe1(device, ioaddr, ioread16(ioaddr + 0xC88) >> 12, edev->id.driver_data, vortex_cards_found)) { - release_region (edev->base_addr, VORTEX_TOTAL_SIZE); + release_region(edev->base_addr, VORTEX_TOTAL_SIZE); return -ENODEV; } @@ -1058,15 +1055,15 @@ static int vortex_eisa_probe (struct device *device) return 0; } -static int vortex_eisa_remove (struct device *device) +static int vortex_eisa_remove(struct device *device) { struct eisa_device *edev; struct net_device *dev; struct vortex_private *vp; void __iomem *ioaddr; - edev = to_eisa_device (device); - dev = eisa_get_drvdata (edev); + edev = to_eisa_device(device); + dev = eisa_get_drvdata(edev); if (!dev) { printk("vortex_eisa_remove called for Compaq device!\n"); @@ -1076,17 +1073,17 @@ static int vortex_eisa_remove (struct device *device) vp = netdev_priv(dev); ioaddr = vp->ioaddr; - unregister_netdev (dev); - iowrite16 (TotalReset|0x14, ioaddr + EL3_CMD); - release_region (dev->base_addr, VORTEX_TOTAL_SIZE); + unregister_netdev(dev); + iowrite16(TotalReset|0x14, ioaddr + EL3_CMD); + release_region(dev->base_addr, VORTEX_TOTAL_SIZE); - free_netdev (dev); + free_netdev(dev); return 0; } #endif /* returns count found (>= 0), or negative on error */ -static int __init vortex_eisa_init (void) +static int __init vortex_eisa_init(void) { int eisa_found = 0; int orig_cards_found = vortex_cards_found; @@ -1117,7 +1114,7 @@ static int __init vortex_eisa_init (void) } /* returns count (>= 0), or negative on error */ -static int __devinit vortex_init_one (struct pci_dev *pdev, +static int __devinit vortex_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { int rc, unit, pci_bar; @@ -1125,7 +1122,7 @@ static int __devinit vortex_init_one (struct pci_dev *pdev, void __iomem *ioaddr; /* wake up and enable device */ - rc = pci_enable_device (pdev); + rc = pci_enable_device(pdev); if (rc < 0) goto out; @@ -1147,7 +1144,7 @@ static int __devinit vortex_init_one (struct pci_dev *pdev, rc = vortex_probe1(&pdev->dev, ioaddr, pdev->irq, ent->driver_data, unit); if (rc < 0) { - pci_disable_device (pdev); + pci_disable_device(pdev); goto out; } @@ -1262,7 +1259,7 @@ static int __devinit vortex_probe1(struct device *gendev, /* enable bus-mastering if necessary */ if (vci->flags & PCI_USES_MASTER) - pci_set_master (pdev); + pci_set_master(pdev); if (vci->drv_flags & IS_VORTEX) { u8 pci_latency; @@ -1306,7 +1303,7 @@ static int __devinit vortex_probe1(struct device *gendev, if (pdev) pci_set_drvdata(pdev, dev); if (edev) - eisa_set_drvdata (edev, dev); + eisa_set_drvdata(edev, dev); vp->media_override = 7; if (option >= 0) { @@ -1808,7 +1805,6 @@ vortex_up(struct net_device *dev) set_8021q_mode(dev, 1); iowrite16(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ -// issue_and_wait(dev, SetTxStart|0x07ff); iowrite16(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ iowrite16(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ /* Allow status bits to be seen. */ @@ -1944,7 +1940,7 @@ vortex_timer(unsigned long data) if (vp->medialock) goto leave_media_alone; - if ( ! ok) { + if (!ok) { unsigned int config; do { @@ -2179,7 +2175,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) if (vp->bus_master) { /* Set the bus-master controller to transfer the packet. */ int len = (skb->len + 3) & ~3; - iowrite32( vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len, PCI_DMA_TODEVICE), + iowrite32(vp->tx_skb_dma = pci_map_single(VORTEX_PCI(vp), skb->data, len, PCI_DMA_TODEVICE), ioaddr + Wn7_MasterAddr); iowrite16(len, ioaddr + Wn7_MasterLen); vp->tx_skb = skb; @@ -3058,7 +3054,7 @@ static struct ethtool_ops vortex_ethtool_ops = { .set_settings = vortex_set_settings, .get_link = ethtool_op_get_link, .nway_reset = vortex_nway_reset, - .get_perm_addr = ethtool_op_get_perm_addr, + .get_perm_addr = ethtool_op_get_perm_addr, }; #ifdef CONFIG_PCI @@ -3259,7 +3255,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val } return; } - + /* ACPI: Advanced Configuration and Power Interface. */ /* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */ static void acpi_set_WOL(struct net_device *dev) @@ -3283,7 +3279,7 @@ static void acpi_set_WOL(struct net_device *dev) } -static void __devexit vortex_remove_one (struct pci_dev *pdev) +static void __devexit vortex_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); struct vortex_private *vp; @@ -3339,7 +3335,7 @@ static int vortex_have_pci; static int vortex_have_eisa; -static int __init vortex_init (void) +static int __init vortex_init(void) { int pci_rc, eisa_rc; @@ -3355,14 +3351,14 @@ static int __init vortex_init (void) } -static void __exit vortex_eisa_cleanup (void) +static void __exit vortex_eisa_cleanup(void) { struct vortex_private *vp; void __iomem *ioaddr; #ifdef CONFIG_EISA /* Take care of the EISA devices */ - eisa_driver_unregister (&vortex_eisa_driver); + eisa_driver_unregister(&vortex_eisa_driver); #endif if (compaq_net_device) { @@ -3370,33 +3366,24 @@ static void __exit vortex_eisa_cleanup (void) ioaddr = ioport_map(compaq_net_device->base_addr, VORTEX_TOTAL_SIZE); - unregister_netdev (compaq_net_device); - iowrite16 (TotalReset, ioaddr + EL3_CMD); + unregister_netdev(compaq_net_device); + iowrite16(TotalReset, ioaddr + EL3_CMD); release_region(compaq_net_device->base_addr, VORTEX_TOTAL_SIZE); - free_netdev (compaq_net_device); + free_netdev(compaq_net_device); } } -static void __exit vortex_cleanup (void) +static void __exit vortex_cleanup(void) { if (vortex_have_pci) - pci_unregister_driver (&vortex_driver); + pci_unregister_driver(&vortex_driver); if (vortex_have_eisa) - vortex_eisa_cleanup (); + vortex_eisa_cleanup(); } module_init(vortex_init); module_exit(vortex_cleanup); - - -/* - * Local variables: - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ -- cgit v1.2.3 From 0b28002fdf2d5b6ce3135a544c04940a16c5b0ba Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 26 Mar 2006 01:38:58 -0800 Subject: [PATCH] more s/fucn/func/ typo fixes s/fucntion/function/ typo fixes Signed-off-by: Akinobu Mita Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/sis900.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 253440a9802..8429ceb0138 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -1693,7 +1693,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance, struct pt_regs * * Process receive interrupt events, * put buffer to higher layer and refill buffer pool - * Note: This fucntion is called by interrupt handler, + * Note: This function is called by interrupt handler, * don't do "too much" work here */ @@ -1840,7 +1840,7 @@ static int sis900_rx(struct net_device *net_dev) * * Check for error condition and free socket buffer etc * schedule for more transmission as needed - * Note: This fucntion is called by interrupt handler, + * Note: This function is called by interrupt handler, * don't do "too much" work here */ -- cgit v1.2.3 From f222313a61a5e134de80767b35c672b91e78383c Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 23 Jan 2006 16:59:58 -0500 Subject: [PATCH] wireless: import bcm43xx sources Import the bcm43xx driver from the upstream sources here: ftp://ftp.berlios.de/pub/bcm43xx/snapshots/bcm43xx/bcm43xx-20060123.tar.bz2 Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/COPYING | 340 ++ drivers/net/wireless/bcm43xx/Makefile | 87 + drivers/net/wireless/bcm43xx/README | 36 + drivers/net/wireless/bcm43xx/bcm43xx.h | 961 +++++ drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 503 +++ drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h | 117 + drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 1009 ++++++ drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 176 + drivers/net/wireless/bcm43xx/bcm43xx_ilt.c | 367 ++ drivers/net/wireless/bcm43xx/bcm43xx_ilt.h | 34 + drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 261 ++ drivers/net/wireless/bcm43xx/bcm43xx_leds.h | 47 + drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4597 ++++++++++++++++++++++++ drivers/net/wireless/bcm43xx/bcm43xx_main.h | 283 ++ drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 2122 +++++++++++ drivers/net/wireless/bcm43xx/bcm43xx_phy.h | 74 + drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 592 +++ drivers/net/wireless/bcm43xx/bcm43xx_pio.h | 88 + drivers/net/wireless/bcm43xx/bcm43xx_power.c | 358 ++ drivers/net/wireless/bcm43xx/bcm43xx_power.h | 47 + drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 1766 +++++++++ drivers/net/wireless/bcm43xx/bcm43xx_radio.h | 93 + drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 1099 ++++++ drivers/net/wireless/bcm43xx/bcm43xx_wx.h | 36 + 24 files changed, 15093 insertions(+) create mode 100644 drivers/net/wireless/bcm43xx/COPYING create mode 100644 drivers/net/wireless/bcm43xx/Makefile create mode 100644 drivers/net/wireless/bcm43xx/README create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_dma.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_dma.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_ilt.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_ilt.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_leds.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_leds.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_main.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_main.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_phy.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_phy.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_pio.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_pio.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_power.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_power.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_radio.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_radio.h create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_wx.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_wx.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/COPYING b/drivers/net/wireless/bcm43xx/COPYING new file mode 100644 index 00000000000..5b6e7c66c27 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile new file mode 100644 index 00000000000..98d4efb1d12 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/Makefile @@ -0,0 +1,87 @@ +# Makefile for bcm43xx driver + +VERSION := 0.0.1 +RELEASE_NAME := bcm43xx-$(VERSION) + +# Optional path, where the SoftMAC subsystem is located. +# You may set SOFTMAC_DIR in your bashrc, for example. +SOFTMAC_DIR ?= + +KVER := $(shell uname -r) +KDIR ?= /lib/modules/$(KVER)/build +PWD := $(shell pwd) +MODPATH := $(DESTDIR)/lib/modules/$(KVER)/kernel/drivers/net/bcm43xx + +# Comment/uncomment to enable/disable debugging +DEBUG = y + + +ifeq ($(DEBUG),y) +DEBUGFS_OBJ = bcm43xx_debugfs.o +CFLAGS += -O2 -DCONFIG_BCM43XX_DEBUG +else +DEBUGFS_OBJ = +CFLAGS += -O2 +endif + +CFLAGS += -DBCM43xx_VERSION=$(VERSION) -I/lib/modules/$(KVER)/include +ifneq ($(SOFTMAC_DIR),) +CPPFLAGS := -I$(SOFTMAC_DIR) $(CPPFLAGS) +endif + +ifneq ($(KERNELRELEASE),) +# call from kernel build system + +obj-m := bcm43xx.o +bcm43xx-objs := bcm43xx_main.o bcm43xx_dma.o $(DEBUGFS_OBJ) \ + bcm43xx_radio.o bcm43xx_phy.o \ + bcm43xx_power.o bcm43xx_wx.o \ + bcm43xx_pio.o bcm43xx_ilt.o \ + bcm43xx_leds.o + +else + +default: modules + +modules: + $(MAKE) -C $(KDIR) M=$(PWD) modules + +install: bcm43xx.ko + install -d $(MODPATH) + install -m 644 -c bcm43xx.ko $(MODPATH) + /sbin/depmod -a + +uninstall: + rm -rf $(MODPATH) + /sbin/depmod -a + +endif + +clean: + find . \( -name '*.ko' -o -name '*.o' -o -name '.tmp_versions' -o -name '*~' -o -name '.*.cmd' \ + -o -name '*.mod.c' -o -name '*.tar.bz2' -o -name '*.rej' -o -name '*.orig' \)\ + -print | xargs rm -Rf + +depend .depend dep: + $(CC) $(CFLAGS) -M *.c > .depend + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + +DISTFILES = $(shell find . \( -not -name '.' \) -print | grep -v "\.tar\.bz2" | grep -v "\/\." ) +DISTDIR = $(RELEASE_NAME) + +release: clean + @rm -rf $(DISTDIR) + @mkdir $(DISTDIR) + @chmod 777 $(DISTDIR) + @for file in $(DISTFILES); do \ + if test -d $$file; then \ + mkdir $(DISTDIR)/$$file; \ + else \ + cp -p $$file $(DISTDIR)/$$file; \ + fi; \ + done + @tar -c $(DISTDIR) | bzip2 -9 > $(RELEASE_NAME).tar.bz2 + @rm -rf $(DISTDIR) diff --git a/drivers/net/wireless/bcm43xx/README b/drivers/net/wireless/bcm43xx/README new file mode 100644 index 00000000000..64d9022de7f --- /dev/null +++ b/drivers/net/wireless/bcm43xx/README @@ -0,0 +1,36 @@ + + BCM43xx Linux Driver Project + ============================ + +About this software +------------------- + +The goal of this project is to develop a linux driver for Broadcom +BCM43xx chips, based on the specification at +http://bcm-specs.sipsolutions.net/ + +The project page is http://bcm43xx.berlios.de/ + + +Requirements +------------ + +1) Linux Kernel 2.6.15 or later + http://www.kernel.org/ + + You may want to configure your kernel with: + + CONFIG_DEBUG_FS (optional): + -> Kernel hacking + -> Debug Filesystem + +2) SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211 + modules: + http://softmac.sipsolutions.net/ + +3) Firmware Files + + Please try fwcutter. Fwcutter can extract the firmware from various + binary driver files. It supports driver files from Windows, MacOS and + Linux. You can get fwcutter from http://bcm43xx.berlios.de/. + Also, fwcutter comes with a README file for further instructions. diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h new file mode 100644 index 00000000000..aca1601e5b4 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -0,0 +1,961 @@ +#ifndef BCM43xx_H_ +#define BCM43xx_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "bcm43xx_debugfs.h" +#include "bcm43xx_leds.h" + + +#define DRV_NAME __stringify(KBUILD_MODNAME) +#define DRV_VERSION __stringify(BCM43xx_VERSION) +#define BCM43xx_DRIVER_NAME DRV_NAME " driver " DRV_VERSION +#define PFX DRV_NAME ": " + +#define BCM43xx_SWITCH_CORE_MAX_RETRIES 10 +#define BCM43xx_IRQWAIT_MAX_RETRIES 50 +#define BCM43xx_TX_TIMEOUT (10 * HZ) + +#define BCM43xx_IO_SIZE 8192 +#define BCM43xx_REG_ACTIVE_CORE 0x80 + +/* Interrupt Control PCI Configuration Register. (Only on PCI cores with rev >= 6) */ +#define BCM43xx_PCICFG_ICR 0x94 +/* SPROM control register. */ +#define BCM43xx_PCICFG_SPROMCTL 0x88 + +/* MMIO offsets */ +#define BCM43xx_MMIO_DMA1_REASON 0x20 +#define BCM43xx_MMIO_DMA1_IRQ_MASK 0x24 +#define BCM43xx_MMIO_DMA2_REASON 0x28 +#define BCM43xx_MMIO_DMA2_IRQ_MASK 0x2C +#define BCM43xx_MMIO_DMA3_REASON 0x30 +#define BCM43xx_MMIO_DMA3_IRQ_MASK 0x34 +#define BCM43xx_MMIO_DMA4_REASON 0x38 +#define BCM43xx_MMIO_DMA4_IRQ_MASK 0x3C +#define BCM43xx_MMIO_STATUS_BITFIELD 0x120 +#define BCM43xx_MMIO_STATUS2_BITFIELD 0x124 +#define BCM43xx_MMIO_GEN_IRQ_REASON 0x128 +#define BCM43xx_MMIO_GEN_IRQ_MASK 0x12C +#define BCM43xx_MMIO_RAM_CONTROL 0x130 +#define BCM43xx_MMIO_RAM_DATA 0x134 +#define BCM43xx_MMIO_PS_STATUS 0x140 +#define BCM43xx_MMIO_RADIO_HWENABLED_HI 0x158 +#define BCM43xx_MMIO_SHM_CONTROL 0x160 +#define BCM43xx_MMIO_SHM_DATA 0x164 +#define BCM43xx_MMIO_SHM_DATA_UNALIGNED 0x166 +#define BCM43xx_MMIO_XMITSTAT_0 0x170 +#define BCM43xx_MMIO_XMITSTAT_1 0x174 +#define BCM43xx_MMIO_REV3PLUS_TSF_LOW 0x180 /* core rev >= 3 only */ +#define BCM43xx_MMIO_REV3PLUS_TSF_HIGH 0x184 /* core rev >= 3 only */ +#define BCM43xx_MMIO_DMA1_BASE 0x200 +#define BCM43xx_MMIO_DMA2_BASE 0x220 +#define BCM43xx_MMIO_DMA3_BASE 0x240 +#define BCM43xx_MMIO_DMA4_BASE 0x260 +#define BCM43xx_MMIO_PIO1_BASE 0x300 +#define BCM43xx_MMIO_PIO2_BASE 0x310 +#define BCM43xx_MMIO_PIO3_BASE 0x320 +#define BCM43xx_MMIO_PIO4_BASE 0x330 +#define BCM43xx_MMIO_PHY_VER 0x3E0 +#define BCM43xx_MMIO_PHY_RADIO 0x3E2 +#define BCM43xx_MMIO_ANTENNA 0x3E8 +#define BCM43xx_MMIO_CHANNEL 0x3F0 +#define BCM43xx_MMIO_CHANNEL_EXT 0x3F4 +#define BCM43xx_MMIO_RADIO_CONTROL 0x3F6 +#define BCM43xx_MMIO_RADIO_DATA_HIGH 0x3F8 +#define BCM43xx_MMIO_RADIO_DATA_LOW 0x3FA +#define BCM43xx_MMIO_PHY_CONTROL 0x3FC +#define BCM43xx_MMIO_PHY_DATA 0x3FE +#define BCM43xx_MMIO_MACFILTER_CONTROL 0x420 +#define BCM43xx_MMIO_MACFILTER_DATA 0x422 +#define BCM43xx_MMIO_RADIO_HWENABLED_LO 0x49A +#define BCM43xx_MMIO_GPIO_CONTROL 0x49C +#define BCM43xx_MMIO_GPIO_MASK 0x49E +#define BCM43xx_MMIO_TSF_0 0x632 /* core rev < 3 only */ +#define BCM43xx_MMIO_TSF_1 0x634 /* core rev < 3 only */ +#define BCM43xx_MMIO_TSF_2 0x636 /* core rev < 3 only */ +#define BCM43xx_MMIO_TSF_3 0x638 /* core rev < 3 only */ +#define BCM43xx_MMIO_POWERUP_DELAY 0x6A8 + +/* SPROM offsets. */ +#define BCM43xx_SPROM_BASE 0x1000 +#define BCM43xx_SPROM_BOARDFLAGS2 0x1c +#define BCM43xx_SPROM_IL0MACADDR 0x24 +#define BCM43xx_SPROM_ET0MACADDR 0x27 +#define BCM43xx_SPROM_ET1MACADDR 0x2a +#define BCM43xx_SPROM_ETHPHY 0x2d +#define BCM43xx_SPROM_BOARDREV 0x2e +#define BCM43xx_SPROM_PA0B0 0x2f +#define BCM43xx_SPROM_PA0B1 0x30 +#define BCM43xx_SPROM_PA0B2 0x31 +#define BCM43xx_SPROM_WL0GPIO0 0x32 +#define BCM43xx_SPROM_WL0GPIO2 0x33 +#define BCM43xx_SPROM_MAXPWR 0x34 +#define BCM43xx_SPROM_PA1B0 0x35 +#define BCM43xx_SPROM_PA1B1 0x36 +#define BCM43xx_SPROM_PA1B2 0x37 +#define BCM43xx_SPROM_IDL_TSSI_TGT 0x38 +#define BCM43xx_SPROM_BOARDFLAGS 0x39 +#define BCM43xx_SPROM_ANTENNA_GAIN 0x3a +#define BCM43xx_SPROM_VERSION 0x3f + +/* BCM43xx_SPROM_BOARDFLAGS values */ +#define BCM43xx_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */ +#define BCM43xx_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */ +#define BCM43xx_BFL_AIRLINEMODE 0x0004 /* implements GPIO 13 radio disable indication */ +#define BCM43xx_BFL_RSSI 0x0008 /* software calculates nrssi slope. */ +#define BCM43xx_BFL_ENETSPI 0x0010 /* has ephy roboswitch spi */ +#define BCM43xx_BFL_XTAL_NOSLOW 0x0020 /* no slow clock available */ +#define BCM43xx_BFL_CCKHIPWR 0x0040 /* can do high power CCK transmission */ +#define BCM43xx_BFL_ENETADM 0x0080 /* has ADMtek switch */ +#define BCM43xx_BFL_ENETVLAN 0x0100 /* can do vlan */ +#define BCM43xx_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */ +#define BCM43xx_BFL_NOPCI 0x0400 /* leaves PCI floating */ +#define BCM43xx_BFL_FEM 0x0800 /* supports the Front End Module */ + +/* GPIO register offset, in both ChipCommon and PCI core. */ +#define BCM43xx_GPIO_CONTROL 0x6c + +/* SHM Routing */ +#define BCM43xx_SHM_SHARED 0x0001 +#define BCM43xx_SHM_WIRELESS 0x0002 +#define BCM43xx_SHM_PCM 0x0003 +#define BCM43xx_SHM_HWMAC 0x0004 +#define BCM43xx_SHM_UCODE 0x0300 + +/* MacFilter offsets. */ +#define BCM43xx_MACFILTER_SELF 0x0000 +#define BCM43xx_MACFILTER_ASSOC 0x0003 + +/* Chipcommon registers. */ +#define BCM43xx_CHIPCOMMON_CAPABILITIES 0x04 +#define BCM43xx_CHIPCOMMON_PLLONDELAY 0xB0 +#define BCM43xx_CHIPCOMMON_FREFSELDELAY 0xB4 +#define BCM43xx_CHIPCOMMON_SLOWCLKCTL 0xB8 +#define BCM43xx_CHIPCOMMON_SYSCLKCTL 0xC0 + +/* PCI core specific registers. */ +#define BCM43xx_PCICORE_BCAST_ADDR 0x50 +#define BCM43xx_PCICORE_BCAST_DATA 0x54 +#define BCM43xx_PCICORE_SBTOPCI2 0x108 + +/* SBTOPCI2 values. */ +#define BCM43xx_SBTOPCI2_PREFETCH 0x4 +#define BCM43xx_SBTOPCI2_BURST 0x8 + +/* Chipcommon capabilities. */ +#define BCM43xx_CAPABILITIES_PCTL 0x00040000 +#define BCM43xx_CAPABILITIES_PLLMASK 0x00030000 +#define BCM43xx_CAPABILITIES_PLLSHIFT 16 +#define BCM43xx_CAPABILITIES_FLASHMASK 0x00000700 +#define BCM43xx_CAPABILITIES_FLASHSHIFT 8 +#define BCM43xx_CAPABILITIES_EXTBUSPRESENT 0x00000040 +#define BCM43xx_CAPABILITIES_UARTGPIO 0x00000020 +#define BCM43xx_CAPABILITIES_UARTCLOCKMASK 0x00000018 +#define BCM43xx_CAPABILITIES_UARTCLOCKSHIFT 3 +#define BCM43xx_CAPABILITIES_MIPSBIGENDIAN 0x00000004 +#define BCM43xx_CAPABILITIES_NRUARTSMASK 0x00000003 + +/* PowerControl */ +#define BCM43xx_PCTL_IN 0xB0 +#define BCM43xx_PCTL_OUT 0xB4 +#define BCM43xx_PCTL_OUTENABLE 0xB8 +#define BCM43xx_PCTL_XTAL_POWERUP 0x40 +#define BCM43xx_PCTL_PLL_POWERDOWN 0x80 + +/* PowerControl Clock Modes */ +#define BCM43xx_PCTL_CLK_FAST 0x00 +#define BCM43xx_PCTL_CLK_SLOW 0x01 +#define BCM43xx_PCTL_CLK_DYNAMIC 0x02 + +#define BCM43xx_PCTL_FORCE_SLOW 0x0800 +#define BCM43xx_PCTL_FORCE_PLL 0x1000 +#define BCM43xx_PCTL_DYN_XTAL 0x2000 + +/* COREIDs */ +#define BCM43xx_COREID_CHIPCOMMON 0x800 +#define BCM43xx_COREID_ILINE20 0x801 +#define BCM43xx_COREID_SDRAM 0x803 +#define BCM43xx_COREID_PCI 0x804 +#define BCM43xx_COREID_MIPS 0x805 +#define BCM43xx_COREID_ETHERNET 0x806 +#define BCM43xx_COREID_V90 0x807 +#define BCM43xx_COREID_USB11_HOSTDEV 0x80a +#define BCM43xx_COREID_IPSEC 0x80b +#define BCM43xx_COREID_PCMCIA 0x80d +#define BCM43xx_COREID_EXT_IF 0x80f +#define BCM43xx_COREID_80211 0x812 +#define BCM43xx_COREID_MIPS_3302 0x816 +#define BCM43xx_COREID_USB11_HOST 0x817 +#define BCM43xx_COREID_USB11_DEV 0x818 +#define BCM43xx_COREID_USB20_HOST 0x819 +#define BCM43xx_COREID_USB20_DEV 0x81a +#define BCM43xx_COREID_SDIO_HOST 0x81b + +/* Core Information Registers */ +#define BCM43xx_CIR_BASE 0xf00 +#define BCM43xx_CIR_SBTPSFLAG (BCM43xx_CIR_BASE + 0x18) +#define BCM43xx_CIR_SBIMSTATE (BCM43xx_CIR_BASE + 0x90) +#define BCM43xx_CIR_SBINTVEC (BCM43xx_CIR_BASE + 0x94) +#define BCM43xx_CIR_SBTMSTATELOW (BCM43xx_CIR_BASE + 0x98) +#define BCM43xx_CIR_SBTMSTATEHIGH (BCM43xx_CIR_BASE + 0x9c) +#define BCM43xx_CIR_SBIMCONFIGLOW (BCM43xx_CIR_BASE + 0xa8) +#define BCM43xx_CIR_SB_ID_HI (BCM43xx_CIR_BASE + 0xfc) + +/* Mask to get the Backplane Flag Number from SBTPSFLAG. */ +#define BCM43xx_BACKPLANE_FLAG_NR_MASK 0x3f + +/* SBIMCONFIGLOW values/masks. */ +#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK 0x00000007 +#define BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT 0 +#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK 0x00000070 +#define BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT 4 +#define BCM43xx_SBIMCONFIGLOW_CONNID_MASK 0x00ff0000 +#define BCM43xx_SBIMCONFIGLOW_CONNID_SHIFT 16 + +/* sbtmstatelow state flags */ +#define BCM43xx_SBTMSTATELOW_RESET 0x01 +#define BCM43xx_SBTMSTATELOW_REJECT 0x02 +#define BCM43xx_SBTMSTATELOW_CLOCK 0x10000 +#define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000 + +/* sbtmstatehigh state flags */ +#define BCM43xx_SBTMSTATEHIGH_SERROR 0x1 +#define BCM43xx_SBTMSTATEHIGH_BUSY 0x4 + +/* sbimstate flags */ +#define BCM43xx_SBIMSTATE_IB_ERROR 0x20000 +#define BCM43xx_SBIMSTATE_TIMEOUT 0x40000 + +/* PHYVersioning */ +#define BCM43xx_PHYTYPE_A 0x00 +#define BCM43xx_PHYTYPE_B 0x01 +#define BCM43xx_PHYTYPE_G 0x02 + +/* PHYRegisters */ +#define BCM43xx_PHY_ILT_A_CTRL 0x0072 +#define BCM43xx_PHY_ILT_A_DATA1 0x0073 +#define BCM43xx_PHY_ILT_A_DATA2 0x0074 +#define BCM43xx_PHY_G_LO_CONTROL 0x0810 +#define BCM43xx_PHY_ILT_G_CTRL 0x0472 +#define BCM43xx_PHY_ILT_G_DATA1 0x0473 +#define BCM43xx_PHY_ILT_G_DATA2 0x0474 +#define BCM43xx_PHY_A_PCTL 0x007B +#define BCM43xx_PHY_G_PCTL 0x0029 +#define BCM43xx_PHY_A_CRS 0x0029 +#define BCM43xx_PHY_RADIO_BITFIELD 0x0401 +#define BCM43xx_PHY_G_CRS 0x0429 +#define BCM43xx_PHY_NRSSILT_CTRL 0x0803 +#define BCM43xx_PHY_NRSSILT_DATA 0x0804 + +/* RadioRegisters */ +#define BCM43xx_RADIOCTL_ID 0x01 + +/* StatusBitField */ +#define BCM43xx_SBF_MAC_ENABLED 0x00000001 +#define BCM43xx_SBF_2 0x00000002 /*FIXME: fix name*/ +#define BCM43xx_SBF_CORE_READY 0x00000004 +#define BCM43xx_SBF_400 0x00000400 /*FIXME: fix name*/ +#define BCM43xx_SBF_4000 0x00004000 /*FIXME: fix name*/ +#define BCM43xx_SBF_8000 0x00008000 /*FIXME: fix name*/ +#define BCM43xx_SBF_XFER_REG_BYTESWAP 0x00010000 +#define BCM43xx_SBF_MODE_NOTADHOC 0x00020000 +#define BCM43xx_SBF_MODE_AP 0x00040000 +#define BCM43xx_SBF_RADIOREG_LOCK 0x00080000 +#define BCM43xx_SBF_MODE_MONITOR 0x00400000 +#define BCM43xx_SBF_MODE_PROMISC 0x01000000 +#define BCM43xx_SBF_PS1 0x02000000 +#define BCM43xx_SBF_PS2 0x04000000 +#define BCM43xx_SBF_NO_SSID_BCAST 0x08000000 +#define BCM43xx_SBF_TIME_UPDATE 0x10000000 +#define BCM43xx_SBF_80000000 0x80000000 /*FIXME: fix name*/ + +/* MicrocodeFlagsBitfield (addr + lo-word values?)*/ +#define BCM43xx_UCODEFLAGS_OFFSET 0x005E + +#define BCM43xx_UCODEFLAG_AUTODIV 0x0001 +#define BCM43xx_UCODEFLAG_UNKBGPHY 0x0002 +#define BCM43xx_UCODEFLAG_UNKBPHY 0x0004 +#define BCM43xx_UCODEFLAG_UNKGPHY 0x0020 +#define BCM43xx_UCODEFLAG_UNKPACTRL 0x0040 +#define BCM43xx_UCODEFLAG_JAPAN 0x0080 + +/* Generic-Interrupt reasons. */ +#define BCM43xx_IRQ_READY (1 << 0) +#define BCM43xx_IRQ_BEACON (1 << 1) +#define BCM43xx_IRQ_PS (1 << 2) +#define BCM43xx_IRQ_REG124 (1 << 5) +#define BCM43xx_IRQ_PMQ (1 << 6) +#define BCM43xx_IRQ_PIO_WORKAROUND (1 << 8) +#define BCM43xx_IRQ_XMIT_ERROR (1 << 11) +#define BCM43xx_IRQ_RX (1 << 15) +#define BCM43xx_IRQ_SCAN (1 << 16) +#define BCM43xx_IRQ_NOISE (1 << 18) +#define BCM43xx_IRQ_XMIT_STATUS (1 << 29) + +#define BCM43xx_IRQ_ALL 0xffffffff +#define BCM43xx_IRQ_INITIAL (BCM43xx_IRQ_PS | \ + BCM43xx_IRQ_REG124 | \ + BCM43xx_IRQ_PMQ | \ + BCM43xx_IRQ_XMIT_ERROR | \ + BCM43xx_IRQ_RX | \ + BCM43xx_IRQ_SCAN | \ + BCM43xx_IRQ_NOISE | \ + BCM43xx_IRQ_XMIT_STATUS) + + +/* Initial default iw_mode */ +#define BCM43xx_INITIAL_IWMODE IW_MODE_INFRA + +/* Values/Masks for the device TX header */ +#define BCM43xx_TXHDRFLAG_EXPECTACK 0x0001 +#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT 0x0008 +#define BCM43xx_TXHDRFLAG_DESTPSMODE 0x0020 +#define BCM43xx_TXHDRFLAG_FALLBACKOFDM 0x0100 +#define BCM43xx_TXHDRFLAG_FRAMEBURST 0x0800 + +#define BCM43xx_TXHDRCTL_OFDM 0x0001 +#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE 0x0010 +#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK 0x0030 +#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT 8 + +#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK 0x00F0 +#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT 4 +#define BCM43xx_TXHDR_WSEC_ALGO_MASK 0x0003 +#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT 0 + +/* Bus type PCI. */ +#define BCM43xx_BUSTYPE_PCI 0 +/* Bus type Silicone Backplane Bus. */ +#define BCM43xx_BUSTYPE_SB 1 +/* Bus type PCMCIA. */ +#define BCM43xx_BUSTYPE_PCMCIA 2 + +/* Threshold values. */ +#define BCM43xx_MIN_RTS_THRESHOLD 1U +#define BCM43xx_MAX_RTS_THRESHOLD 2304U +#define BCM43xx_DEFAULT_RTS_THRESHOLD BCM43xx_MAX_RTS_THRESHOLD + +#define BCM43xx_DEFAULT_SHORT_RETRY_LIMIT 7 +#define BCM43xx_DEFAULT_LONG_RETRY_LIMIT 4 + +/* Max size of a security key */ +#define BCM43xx_SEC_KEYSIZE 16 +/* Security algorithms. */ +enum { + BCM43xx_SEC_ALGO_NONE = 0, /* unencrypted, as of TX header. */ + BCM43xx_SEC_ALGO_WEP, + BCM43xx_SEC_ALGO_UNKNOWN, + BCM43xx_SEC_ALGO_AES, + BCM43xx_SEC_ALGO_WEP104, + BCM43xx_SEC_ALGO_TKIP, +}; + +#ifdef assert +# undef assert +#endif +#ifdef CONFIG_BCM43XX_DEBUG +#define assert(expr) \ + do { \ + if (unlikely(!(expr))) { \ + printk(KERN_ERR PFX "ASSERTION FAILED (%s) at: %s:%d:%s()\n", \ + #expr, __FILE__, __LINE__, __FUNCTION__); \ + } \ + } while (0) +#else +#define assert(expr) do { /* nothing */ } while (0) +#endif + +/* rate limited printk(). */ +#ifdef printkl +# undef printkl +#endif +#define printkl(f, x...) do { if (printk_ratelimit()) printk(f ,##x); } while (0) +/* rate limited printk() for debugging */ +#ifdef dprintkl +# undef dprintkl +#endif +#ifdef CONFIG_BCM43XX_DEBUG +# define dprintkl printkl +#else +# define dprintkl(f, x...) do { /* nothing */ } while (0) +#endif + +/* Helper macro for if branches. + * An if branch marked with this macro is only taken in DEBUG mode. + * Example: + * if (DEBUG_ONLY(foo == bar)) { + * do something + * } + * In DEBUG mode, the branch will be taken if (foo == bar). + * In non-DEBUG mode, the branch will never be taken. + */ +#ifdef DEBUG_ONLY +# undef DEBUG_ONLY +#endif +#ifdef CONFIG_BCM43XX_DEBUG +# define DEBUG_ONLY(x) (x) +#else +# define DEBUG_ONLY(x) 0 +#endif + +/* debugging printk() */ +#ifdef dprintk +# undef dprintk +#endif +#ifdef CONFIG_BCM43XX_DEBUG +# define dprintk(f, x...) do { printk(f ,##x); } while (0) +#else +# define dprintk(f, x...) do { /* nothing */ } while (0) +#endif + + +struct net_device; +struct pci_dev; +struct workqueue_struct; +struct bcm43xx_dmaring; +struct bcm43xx_pioqueue; + +struct bcm43xx_initval { + u16 offset; + u16 size; + u32 value; +} __attribute__((__packed__)); + +/* Values for bcm430x_sprominfo.locale */ +enum { + BCM43xx_LOCALE_WORLD = 0, + BCM43xx_LOCALE_THAILAND, + BCM43xx_LOCALE_ISRAEL, + BCM43xx_LOCALE_JORDAN, + BCM43xx_LOCALE_CHINA, + BCM43xx_LOCALE_JAPAN, + BCM43xx_LOCALE_USA_CANADA_ANZ, + BCM43xx_LOCALE_EUROPE, + BCM43xx_LOCALE_USA_LOW, + BCM43xx_LOCALE_JAPAN_HIGH, + BCM43xx_LOCALE_ALL, + BCM43xx_LOCALE_NONE, +}; + +#define BCM43xx_SPROM_SIZE 64 /* in 16-bit words. */ +struct bcm43xx_sprominfo { + u16 boardflags2; + u8 il0macaddr[6]; + u8 et0macaddr[6]; + u8 et1macaddr[6]; + u8 et0phyaddr:5; + u8 et1phyaddr:5; + u8 et0mdcport:1; + u8 et1mdcport:1; + u8 boardrev; + u8 locale:4; + u8 antennas_aphy:2; + u8 antennas_bgphy:2; + u16 pa0b0; + u16 pa0b1; + u16 pa0b2; + u8 wl0gpio0; + u8 wl0gpio1; + u8 wl0gpio2; + u8 wl0gpio3; + u8 maxpower_aphy; + u8 maxpower_bgphy; + u16 pa1b0; + u16 pa1b1; + u16 pa1b2; + u8 idle_tssi_tgt_aphy; + u8 idle_tssi_tgt_bgphy; + u16 boardflags; + u16 antennagain_aphy; + u16 antennagain_bgphy; +}; + +/* Value pair to measure the LocalOscillator. */ +struct bcm43xx_lopair { + s8 low; + s8 high; + u8 used:1; +}; +#define BCM43xx_LO_COUNT (14*4) + +struct bcm43xx_phyinfo { + /* Hardware Data */ + u8 version; + u8 type; + u8 rev; + u16 antenna_diversity; + u16 savedpctlreg; + u16 minlowsig[2]; + u16 minlowsigpos[2]; + u8 connected:1, + calibrated:1, + is_locked:1, /* used in bcm43xx_phy_{un}lock() */ + dyn_tssi_tbl:1; /* used in bcm43xx_phy_init_tssi2dbm_table() */ + /* LO Measurement Data. + * Use bcm43xx_get_lopair() to get a value. + */ + struct bcm43xx_lopair *_lo_pairs; + + /* TSSI to dBm table in use */ + const s8 *tssi2dbm; + /* idle TSSI value */ + s8 idle_tssi; + /* PHY lock for core.rev < 3 + * This lock is only used by bcm43xx_phy_{un}lock() + */ + spinlock_t lock; +}; + + +struct bcm43xx_radioinfo { + u16 manufact; + u16 version; + u8 revision; + + /* 0: baseband attenuation, + * 1: radio attenuation, + * 2: tx_CTL1 + * 3: tx_CTL2 + */ + u16 txpower[4]; + /* Current Interference Mitigation mode */ + int interfmode; + /* Stack of saved values from the Interference Mitigation code */ + u16 interfstack[20]; + /* Saved values from the NRSSI Slope calculation */ + s16 nrssi[2]; + s32 nrssislope; + /* In memory nrssi lookup table. */ + s8 nrssi_lt[64]; + + /* current channel */ + u8 channel; + u8 initial_channel; + + u16 lofcal; + + u16 initval; + + u8 enabled:1; + /* ACI (adjacent channel interference) flags. */ + u8 aci_enable:1, + aci_wlan_automatic:1, + aci_hw_rssi:1; +}; + +/* Data structures for DMA transmission, per 80211 core. */ +struct bcm43xx_dma { + struct bcm43xx_dmaring *tx_ring0; + struct bcm43xx_dmaring *tx_ring1; + struct bcm43xx_dmaring *tx_ring2; + struct bcm43xx_dmaring *tx_ring3; + struct bcm43xx_dmaring *rx_ring0; + struct bcm43xx_dmaring *rx_ring1; /* only available on core.rev < 5 */ +}; + +/* Data structures for PIO transmission, per 80211 core. */ +struct bcm43xx_pio { + struct bcm43xx_pioqueue *queue0; + struct bcm43xx_pioqueue *queue1; + struct bcm43xx_pioqueue *queue2; + struct bcm43xx_pioqueue *queue3; +}; + +#define BCM43xx_MAX_80211_CORES 2 + +#define BCM43xx_COREFLAG_AVAILABLE (1 << 0) +#define BCM43xx_COREFLAG_ENABLED (1 << 1) +#define BCM43xx_COREFLAG_INITIALIZED (1 << 2) + +#ifdef CONFIG_BCM947XX +#define core_offset(bcm) (bcm)->current_core_offset +#else +#define core_offset(bcm) 0 +#endif + +struct bcm43xx_coreinfo { + /** Driver internal flags. See BCM43xx_COREFLAG_* */ + u32 flags; + /** core_id ID number */ + u16 id; + /** core_rev revision number */ + u8 rev; + /** Index number for _switch_core() */ + u8 index; + /* Pointer to the PHYinfo, which belongs to this core (if 80211 core) */ + struct bcm43xx_phyinfo *phy; + /* Pointer to the RadioInfo, which belongs to this core (if 80211 core) */ + struct bcm43xx_radioinfo *radio; + /* Pointer to the DMA rings, which belong to this core (if 80211 core) */ + struct bcm43xx_dma *dma; + /* Pointer to the PIO queues, which belong to this core (if 80211 core) */ + struct bcm43xx_pio *pio; +}; + +/* Context information for a noise calculation (Link Quality). */ +struct bcm43xx_noise_calculation { + struct bcm43xx_coreinfo *core_at_start; + u8 channel_at_start; + u8 calculation_running:1; + u8 nr_samples; + s8 samples[8][4]; +}; + +struct bcm43xx_stats { + u8 link_quality; + /* Store the last TX/RX times here for updating the leds. */ + unsigned long last_tx; + unsigned long last_rx; +}; + +struct bcm43xx_key { + u8 enabled:1; + u8 algorithm; +}; + +struct bcm43xx_private { + struct ieee80211_device *ieee; + struct ieee80211softmac_device *softmac; + + struct net_device *net_dev; + struct pci_dev *pci_dev; + unsigned int irq; + + void __iomem *mmio_addr; + unsigned int mmio_len; + + spinlock_t lock; + + /* Driver status flags. */ + u32 initialized:1, /* init_board() succeed */ + was_initialized:1, /* for PCI suspend/resume. */ + shutting_down:1, /* free_board() in progress */ + pio_mode:1, /* PIO (if true), or DMA (if false) used. */ + bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ + reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ + powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */ + short_preamble:1, /* TRUE, if short preamble is enabled. */ + firmware_norelease:1; /* Do not release the firmware. Used on suspend. */ + + struct bcm43xx_stats stats; + + /* Bus type we are connected to. + * This is currently always BCM43xx_BUSTYPE_PCI + */ + u8 bustype; + + u16 board_vendor; + u16 board_type; + u16 board_revision; + + u16 chip_id; + u8 chip_rev; + + struct bcm43xx_sprominfo sprom; +#define BCM43xx_NR_LEDS 4 + struct bcm43xx_led leds[BCM43xx_NR_LEDS]; + + /* The currently active core. NULL if not initialized, yet. */ + struct bcm43xx_coreinfo *current_core; +#ifdef CONFIG_BCM947XX + /** current core memory offset */ + u32 current_core_offset; +#endif + struct bcm43xx_coreinfo *active_80211_core; + /* coreinfo structs for all possible cores follow. + * Note that a core might not exist. + * So check the coreinfo flags before using it. + */ + struct bcm43xx_coreinfo core_chipcommon; + struct bcm43xx_coreinfo core_pci; + struct bcm43xx_coreinfo core_v90; + struct bcm43xx_coreinfo core_pcmcia; + struct bcm43xx_coreinfo core_ethernet; + struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ]; + /* Info about the PHY for each 80211 core. */ + struct bcm43xx_phyinfo phy[ BCM43xx_MAX_80211_CORES ]; + /* Info about the Radio for each 80211 core. */ + struct bcm43xx_radioinfo radio[ BCM43xx_MAX_80211_CORES ]; + /* DMA */ + struct bcm43xx_dma dma[ BCM43xx_MAX_80211_CORES ]; + /* PIO */ + struct bcm43xx_pio pio[ BCM43xx_MAX_80211_CORES ]; + + u32 chipcommon_capabilities; + + /* Reason code of the last interrupt. */ + u32 irq_reason; + u32 dma_reason[4]; + /* saved irq enable/disable state bitfield. */ + u32 irq_savedstate; + /* Link Quality calculation context. */ + struct bcm43xx_noise_calculation noisecalc; + + /* Threshold values. */ + //TODO: The RTS thr has to be _used_. Currently, it is only set via WX. + u32 rts_threshold; + + /* Interrupt Service Routine tasklet (bottom-half) */ + struct tasklet_struct isr_tasklet; + /* Custom driver work queue. */ + struct workqueue_struct *workqueue; + + /* Periodic tasks */ + struct work_struct periodic_work0; +#define BCM43xx_PERIODIC_0_DELAY (HZ * 15) + struct work_struct periodic_work1; +#define BCM43xx_PERIODIC_1_DELAY ((HZ * 60) + HZ / 2) + struct work_struct periodic_work2; +#define BCM43xx_PERIODIC_2_DELAY ((HZ * 120) + HZ) + struct work_struct periodic_work3; +#define BCM43xx_PERIODIC_3_DELAY ((HZ * 30) + HZ / 5) + + struct work_struct restart_work; + + /* Informational stuff. */ + char nick[IW_ESSID_MAX_SIZE + 1]; + + /* encryption/decryption */ + u16 security_offset; + struct bcm43xx_key key[54]; + u8 default_key_idx; + + /* Firmware. */ + const struct firmware *ucode; + const struct firmware *pcm; + const struct firmware *initvals0; + const struct firmware *initvals1; + + /* Debugging stuff follows. */ +#ifdef CONFIG_BCM43XX_DEBUG + struct bcm43xx_dfsentry *dfsentry; + atomic_t mmio_print_cnt; + atomic_t pcicfg_print_cnt; +#endif +}; + +static inline +struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) +{ + return ieee80211softmac_priv(dev); +} + +static inline +int bcm43xx_num_80211_cores(struct bcm43xx_private *bcm) +{ + int i, cnt = 0; + + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + if (bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE) + cnt++; + } + + return cnt; +} + +/* Are we running in init_board() context? */ +static inline +int bcm43xx_is_initializing(struct bcm43xx_private *bcm) +{ + if (bcm->initialized) + return 0; + if (bcm->shutting_down) + return 0; + return 1; +} + +static inline +struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy, + u16 radio_attenuation, + u16 baseband_attenuation) +{ + return phy->_lo_pairs + (radio_attenuation + 14 * (baseband_attenuation / 2)); +} + + +/* MMIO read/write functions. Debug and non-debug variants. */ +#ifdef CONFIG_BCM43XX_DEBUG + +static inline +u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset) +{ + u16 value; + + value = ioread16(bcm->mmio_addr + core_offset(bcm) + offset); + if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { + printk(KERN_INFO PFX "ioread16 offset: 0x%04x, value: 0x%04x\n", + offset, value); + } + + return value; +} + +static inline +void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value) +{ + iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset); + if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { + printk(KERN_INFO PFX "iowrite16 offset: 0x%04x, value: 0x%04x\n", + offset, value); + } +} + +static inline +u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset) +{ + u32 value; + + value = ioread32(bcm->mmio_addr + core_offset(bcm) + offset); + if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { + printk(KERN_INFO PFX "ioread32 offset: 0x%04x, value: 0x%08x\n", + offset, value); + } + + return value; +} + +static inline +void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value) +{ + iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset); + if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { + printk(KERN_INFO PFX "iowrite32 offset: 0x%04x, value: 0x%08x\n", + offset, value); + } +} + +static inline +int bcm43xx_pci_read_config16(struct bcm43xx_private *bcm, int offset, u16 *value) +{ + int err; + + err = pci_read_config_word(bcm->pci_dev, offset, value); + if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { + printk(KERN_INFO PFX "pciread16 offset: 0x%08x, value: 0x%04x, err: %d\n", + offset, *value, err); + } + + return err; +} + +static inline +int bcm43xx_pci_read_config32(struct bcm43xx_private *bcm, int offset, u32 *value) +{ + int err; + + err = pci_read_config_dword(bcm->pci_dev, offset, value); + if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { + printk(KERN_INFO PFX "pciread32 offset: 0x%08x, value: 0x%08x, err: %d\n", + offset, *value, err); + } + + return err; +} + +static inline +int bcm43xx_pci_write_config16(struct bcm43xx_private *bcm, int offset, u16 value) +{ + int err; + + err = pci_write_config_word(bcm->pci_dev, offset, value); + if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { + printk(KERN_INFO PFX "pciwrite16 offset: 0x%08x, value: 0x%04x, err: %d\n", + offset, value, err); + } + + return err; +} + +static inline +int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 value) +{ + int err; + + err = pci_write_config_dword(bcm->pci_dev, offset, value); + if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { + printk(KERN_INFO PFX "pciwrite32 offset: 0x%08x, value: 0x%08x, err: %d\n", + offset, value, err); + } + + return err; +} + +#define bcm43xx_mmioprint_initial(bcm, value) atomic_set(&(bcm)->mmio_print_cnt, (value)) +#define bcm43xx_mmioprint_enable(bcm) atomic_inc(&(bcm)->mmio_print_cnt) +#define bcm43xx_mmioprint_disable(bcm) atomic_dec(&(bcm)->mmio_print_cnt) +#define bcm43xx_pciprint_initial(bcm, value) atomic_set(&(bcm)->pcicfg_print_cnt, (value)) +#define bcm43xx_pciprint_enable(bcm) atomic_inc(&(bcm)->pcicfg_print_cnt) +#define bcm43xx_pciprint_disable(bcm) atomic_dec(&(bcm)->pcicfg_print_cnt) + +#else /* CONFIG_BCM43XX_DEBUG*/ + +#define bcm43xx_read16(bcm, offset) ioread16((bcm)->mmio_addr + core_offset(bcm) + (offset)) +#define bcm43xx_write16(bcm, offset, value) iowrite16((value), (bcm)->mmio_addr + core_offset(bcm) + (offset)) +#define bcm43xx_read32(bcm, offset) ioread32((bcm)->mmio_addr + core_offset(bcm) + (offset)) +#define bcm43xx_write32(bcm, offset, value) iowrite32((value), (bcm)->mmio_addr + core_offset(bcm) + (offset)) +#define bcm43xx_pci_read_config16(bcm, o, v) pci_read_config_word((bcm)->pci_dev, (o), (v)) +#define bcm43xx_pci_read_config32(bcm, o, v) pci_read_config_dword((bcm)->pci_dev, (o), (v)) +#define bcm43xx_pci_write_config16(bcm, o, v) pci_write_config_word((bcm)->pci_dev, (o), (v)) +#define bcm43xx_pci_write_config32(bcm, o, v) pci_write_config_dword((bcm)->pci_dev, (o), (v)) + +#define bcm43xx_mmioprint_initial(x, y) do { /* nothing */ } while (0) +#define bcm43xx_mmioprint_enable(x) do { /* nothing */ } while (0) +#define bcm43xx_mmioprint_disable(x) do { /* nothing */ } while (0) +#define bcm43xx_pciprint_initial(bcm, value) do { /* nothing */ } while (0) +#define bcm43xx_pciprint_enable(bcm) do { /* nothing */ } while (0) +#define bcm43xx_pciprint_disable(bcm) do { /* nothing */ } while (0) + +#endif /* CONFIG_BCM43XX_DEBUG*/ + + +/** Limit a value between two limits */ +#ifdef limit_value +# undef limit_value +#endif +#define limit_value(value, min, max) \ + ({ \ + typeof(value) __value = (value); \ + typeof(value) __min = (min); \ + typeof(value) __max = (max); \ + if (__value < __min) \ + __value = __min; \ + else if (__value > __max) \ + __value = __max; \ + __value; \ + }) + + +/* + * Compatibility stuff follows + */ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15) +# error "The bcm43xx driver does not support kernels < 2.6.15" +# error "The driver will _NOT_ compile on your kernel. Please upgrade to the latest 2.6 kernel." +# error "DO NOT COMPLAIN ABOUT BUGS. UPDATE FIRST AND TRY AGAIN." +#else +# if !defined(CONFIG_IEEE80211_MODULE) && !defined(CONFIG_IEEE80211) +# error "Generic IEEE 802.11 Networking Stack (CONFIG_IEEE80211) not available." +# endif +#endif +#ifdef IEEE80211SOFTMAC_API +# if IEEE80211SOFTMAC_API != 0 +# warning "Incompatible SoftMAC subsystem installed." +# endif +#else +# error "The bcm43xx driver requires the SoftMAC subsystem." +# error "SEE >>>>>> http://softmac.sipsolutions.net/ <<<<<<" +#endif + +#endif /* BCM43xx_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c new file mode 100644 index 00000000000..f8cfc84ca0d --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -0,0 +1,503 @@ +/* + + Broadcom BCM43xx wireless driver + + debugfs driver debugging code + + Copyright (c) 2005 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + + + +#include +#include +#include +#include +#include +#include + +#include "bcm43xx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_debugfs.h" +#include "bcm43xx_dma.h" +#include "bcm43xx_pio.h" + +#define REALLY_BIG_BUFFER_SIZE (1024*256) + +static struct bcm43xx_debugfs fs; +static char really_big_buffer[REALLY_BIG_BUFFER_SIZE]; +static DECLARE_MUTEX(big_buffer_sem); + + +static ssize_t write_file_dummy(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + return count; +} + +static int open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->u.generic_ip; + return 0; +} + +#define fappend(fmt, x...) pos += snprintf(buf + pos, len - pos, fmt , ##x) + +static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + struct net_device *net_dev; + struct pci_dev *pci_dev; + unsigned long flags; + u16 tmp16; + int i; + + down(&big_buffer_sem); + + spin_lock_irqsave(&bcm->lock, flags); + if (!bcm->initialized) { + fappend("Board not initialized.\n"); + goto out; + } + net_dev = bcm->net_dev; + pci_dev = bcm->pci_dev; + + /* This is where the information is written to the "devinfo" file */ + fappend("*** %s devinfo ***\n", net_dev->name); + fappend("vendor: 0x%04x device: 0x%04x\n", + pci_dev->vendor, pci_dev->device); + fappend("subsystem_vendor: 0x%04x subsystem_device: 0x%04x\n", + pci_dev->subsystem_vendor, pci_dev->subsystem_device); + fappend("IRQ: %d\n", bcm->irq); + fappend("mmio_addr: 0x%p mmio_len: %u\n", bcm->mmio_addr, bcm->mmio_len); + fappend("chip_id: 0x%04x chip_rev: 0x%02x\n", bcm->chip_id, bcm->chip_rev); + if ((bcm->core_80211[0].rev >= 3) && (bcm43xx_read32(bcm, 0x0158) & (1 << 16))) + fappend("Radio disabled by hardware!\n"); + if ((bcm->core_80211[0].rev < 3) && !(bcm43xx_read16(bcm, 0x049A) & (1 << 4))) + fappend("Radio disabled by hardware!\n"); + fappend("board_vendor: 0x%04x board_type: 0x%04x\n", bcm->board_vendor, + bcm->board_type); + + fappend("\nCores:\n"); +#define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, " \ + "rev: 0x%02x, index: 0x%02x\n", \ + (info).flags & BCM43xx_COREFLAG_AVAILABLE \ + ? "available" : "nonavailable", \ + (info).flags & BCM43xx_COREFLAG_ENABLED \ + ? "enabled" : "disabled", \ + (info).id, (info).rev, (info).index) + fappend_core("CHIPCOMMON", bcm->core_chipcommon); + fappend_core("PCI", bcm->core_pci); + fappend_core("V90", bcm->core_v90); + fappend_core("PCMCIA", bcm->core_pcmcia); + fappend_core("ETHERNET", bcm->core_ethernet); + fappend_core("first 80211", bcm->core_80211[0]); + fappend_core("second 80211", bcm->core_80211[1]); +#undef fappend_core + tmp16 = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); + fappend("LEDs: "); + for (i = 0; i < BCM43xx_NR_LEDS; i++) + fappend("%d ", !!(tmp16 & (1 << i))); + fappend("\n"); + +out: + spin_unlock_irqrestore(&bcm->lock, flags); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + up(&big_buffer_sem); + return res; +} + +static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + + down(&big_buffer_sem); + + /* This is where the information is written to the "driver" file */ + fappend(BCM43xx_DRIVER_NAME "\n"); + fappend("Compiled at: %s %s\n", __DATE__, __TIME__); + + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + up(&big_buffer_sem); + return res; +} + +static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + unsigned long flags; + + down(&big_buffer_sem); + spin_lock_irqsave(&bcm->lock, flags); + if (!bcm->initialized) { + fappend("Board not initialized.\n"); + goto out; + } + + /* This is where the information is written to the "sprom_dump" file */ + fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); + +out: + spin_unlock_irqrestore(&bcm->lock, flags); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + up(&big_buffer_sem); + return res; +} + +static ssize_t tsf_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + unsigned long flags; + u64 tsf; + + down(&big_buffer_sem); + spin_lock_irqsave(&bcm->lock, flags); + if (!bcm->initialized) { + fappend("Board not initialized.\n"); + goto out; + } + bcm43xx_tsf_read(bcm, &tsf); + fappend("0x%08x%08x\n", + (unsigned int)((tsf & 0xFFFFFFFF00000000ULL) >> 32), + (unsigned int)(tsf & 0xFFFFFFFFULL)); + +out: + spin_unlock_irqrestore(&bcm->lock, flags); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + up(&big_buffer_sem); + return res; +} + +static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + ssize_t buf_size; + ssize_t res; + unsigned long flags; + u64 tsf; + + buf_size = min(count, sizeof (really_big_buffer) - 1); + down(&big_buffer_sem); + if (copy_from_user(buf, user_buf, buf_size)) { + res = -EFAULT; + goto out_up; + } + spin_lock_irqsave(&bcm->lock, flags); + if (!bcm->initialized) { + printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); + res = -EFAULT; + goto out_unlock; + } + if (sscanf(buf, "%lli", &tsf) != 1) { + printk(KERN_INFO PFX "debugfs: invalid values for \"tsf\"\n"); + res = -EINVAL; + goto out_unlock; + } + bcm43xx_tsf_write(bcm, tsf); + res = buf_size; + +out_unlock: + spin_unlock_irqrestore(&bcm->lock, flags); +out_up: + up(&big_buffer_sem); + return res; +} + +static ssize_t txstat_read_file(struct file *file, char __user *userbuf, + size_t count, loff_t *ppos) +{ + const size_t len = REALLY_BIG_BUFFER_SIZE; + + struct bcm43xx_private *bcm = file->private_data; + char *buf = really_big_buffer; + size_t pos = 0; + ssize_t res; + unsigned long flags; + struct bcm43xx_dfsentry *e; + struct bcm43xx_xmitstatus *status; + int i, cnt, j = 0; + + down(&big_buffer_sem); + spin_lock_irqsave(&bcm->lock, flags); + + fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", + BCM43xx_NR_LOGGED_XMITSTATUS); + e = bcm->dfsentry; + if (e->xmitstatus_printing == 0) { + /* At the beginning, make a copy of all data to avoid + * concurrency, as this function is called multiple + * times for big logs. Without copying, the data might + * change between reads. This would result in total trash. + */ + e->xmitstatus_printing = 1; + e->saved_xmitstatus_ptr = e->xmitstatus_ptr; + e->saved_xmitstatus_cnt = e->xmitstatus_cnt; + memcpy(e->xmitstatus_print_buffer, e->xmitstatus_buffer, + BCM43xx_NR_LOGGED_XMITSTATUS * sizeof(*(e->xmitstatus_buffer))); + } + i = e->saved_xmitstatus_ptr - 1; + if (i < 0) + i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; + cnt = e->saved_xmitstatus_cnt; + while (cnt) { + status = e->xmitstatus_print_buffer + i; + fappend("0x%02x: cookie: 0x%04x, flags: 0x%02x, " + "cnt1: 0x%02x, cnt2: 0x%02x, seq: 0x%04x, " + "unk: 0x%04x\n", j, + status->cookie, status->flags, + status->cnt1, status->cnt2, status->seq, + status->unknown); + j++; + cnt--; + i--; + if (i < 0) + i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; + } + + spin_unlock_irqrestore(&bcm->lock, flags); + res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); + spin_lock_irqsave(&bcm->lock, flags); + if (*ppos == pos) { + /* Done. Drop the copied data. */ + e->xmitstatus_printing = 0; + } + spin_unlock_irqrestore(&bcm->lock, flags); + up(&big_buffer_sem); + return res; +} + +#undef fappend + + +static struct file_operations devinfo_fops = { + .read = devinfo_read_file, + .write = write_file_dummy, + .open = open_file_generic, +}; + +static struct file_operations spromdump_fops = { + .read = spromdump_read_file, + .write = write_file_dummy, + .open = open_file_generic, +}; + +static struct file_operations drvinfo_fops = { + .read = drvinfo_read_file, + .write = write_file_dummy, + .open = open_file_generic, +}; + +static struct file_operations tsf_fops = { + .read = tsf_read_file, + .write = tsf_write_file, + .open = open_file_generic, +}; + +static struct file_operations txstat_fops = { + .read = txstat_read_file, + .write = write_file_dummy, + .open = open_file_generic, +}; + + +void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) +{ + struct bcm43xx_dfsentry *e; + char devdir[IFNAMSIZ]; + + assert(bcm); + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) { + printk(KERN_ERR PFX "out of memory\n"); + return; + } + e->bcm = bcm; + e->xmitstatus_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS + * sizeof(*(e->xmitstatus_buffer)), + GFP_KERNEL); + if (!e->xmitstatus_buffer) { + printk(KERN_ERR PFX "out of memory\n"); + kfree(e); + return; + } + e->xmitstatus_print_buffer = kzalloc(BCM43xx_NR_LOGGED_XMITSTATUS + * sizeof(*(e->xmitstatus_buffer)), + GFP_KERNEL); + if (!e->xmitstatus_print_buffer) { + printk(KERN_ERR PFX "out of memory\n"); + kfree(e); + return; + } + + + bcm->dfsentry = e; + + strncpy(devdir, bcm->net_dev->name, ARRAY_SIZE(devdir)); + e->subdir = debugfs_create_dir(devdir, fs.root); + e->dentry_devinfo = debugfs_create_file("devinfo", 0444, e->subdir, + bcm, &devinfo_fops); + if (!e->dentry_devinfo) + printk(KERN_ERR PFX "debugfs: creating \"devinfo\" for \"%s\" failed!\n", devdir); + e->dentry_spromdump = debugfs_create_file("sprom_dump", 0444, e->subdir, + bcm, &spromdump_fops); + if (!e->dentry_spromdump) + printk(KERN_ERR PFX "debugfs: creating \"sprom_dump\" for \"%s\" failed!\n", devdir); + e->dentry_tsf = debugfs_create_file("tsf", 0666, e->subdir, + bcm, &tsf_fops); + if (!e->dentry_tsf) + printk(KERN_ERR PFX "debugfs: creating \"tsf\" for \"%s\" failed!\n", devdir); + e->dentry_txstat = debugfs_create_file("tx_status", 0444, e->subdir, + bcm, &txstat_fops); + if (!e->dentry_txstat) + printk(KERN_ERR PFX "debugfs: creating \"tx_status\" for \"%s\" failed!\n", devdir); +} + +void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) +{ + struct bcm43xx_dfsentry *e; + + if (!bcm) + return; + + e = bcm->dfsentry; + assert(e); + debugfs_remove(e->dentry_spromdump); + debugfs_remove(e->dentry_devinfo); + debugfs_remove(e->dentry_tsf); + debugfs_remove(e->dentry_txstat); + debugfs_remove(e->subdir); + kfree(e->xmitstatus_buffer); + kfree(e->xmitstatus_print_buffer); + kfree(e); +} + +void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ + struct bcm43xx_dfsentry *e; + struct bcm43xx_xmitstatus *savedstatus; + + /* This is protected by bcm->lock */ + e = bcm->dfsentry; + assert(e); + savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr; + memcpy(savedstatus, status, sizeof(*status)); + e->xmitstatus_ptr++; + if (e->xmitstatus_ptr >= BCM43xx_NR_LOGGED_XMITSTATUS) + e->xmitstatus_ptr = 0; + if (e->xmitstatus_cnt < BCM43xx_NR_LOGGED_XMITSTATUS) + e->xmitstatus_cnt++; +} + +void bcm43xx_debugfs_init(void) +{ + memset(&fs, 0, sizeof(fs)); + fs.root = debugfs_create_dir(DRV_NAME, NULL); + if (!fs.root) + printk(KERN_ERR PFX "debugfs: creating \"" DRV_NAME "\" subdir failed!\n"); + fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops); + if (!fs.dentry_driverinfo) + printk(KERN_ERR PFX "debugfs: creating \"" DRV_NAME "/driver\" failed!\n"); +} + +void bcm43xx_debugfs_exit(void) +{ + debugfs_remove(fs.dentry_driverinfo); + debugfs_remove(fs.root); +} + +void bcm43xx_printk_dump(const char *data, + size_t size, + const char *description) +{ + size_t i; + char c; + + printk(KERN_INFO PFX "Data dump (%s, %u bytes):", + description, size); + for (i = 0; i < size; i++) { + c = data[i]; + if (i % 8 == 0) + printk("\n" KERN_INFO PFX "0x%08x: 0x%02x, ", i, c & 0xff); + else + printk("0x%02x, ", c & 0xff); + } + printk("\n"); +} + +void bcm43xx_printk_bitdump(const unsigned char *data, + size_t bytes, int msb_to_lsb, + const char *description) +{ + size_t i; + int j; + const unsigned char *d; + + printk(KERN_INFO PFX "*** Bitdump (%s, %u bytes, %s) ***", + description, bytes, msb_to_lsb ? "MSB to LSB" : "LSB to MSB"); + for (i = 0; i < bytes; i++) { + d = data + i; + if (i % 8 == 0) + printk("\n" KERN_INFO PFX "0x%08x: ", i); + if (msb_to_lsb) { + for (j = 7; j >= 0; j--) { + if (*d & (1 << j)) + printk("1"); + else + printk("0"); + } + } else { + for (j = 0; j < 8; j++) { + if (*d & (1 << j)) + printk("1"); + else + printk("0"); + } + } + printk(" "); + } + printk("\n"); +} + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h new file mode 100644 index 00000000000..50ce267f794 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.h @@ -0,0 +1,117 @@ +#ifndef BCM43xx_DEBUGFS_H_ +#define BCM43xx_DEBUGFS_H_ + +struct bcm43xx_private; +struct bcm43xx_xmitstatus; + +#ifdef CONFIG_BCM43XX_DEBUG + +#include +#include + +struct dentry; + +/* limited by the size of the "really_big_buffer" */ +#define BCM43xx_NR_LOGGED_XMITSTATUS 100 + +struct bcm43xx_dfsentry { + struct dentry *subdir; + struct dentry *dentry_devinfo; + struct dentry *dentry_spromdump; + struct dentry *dentry_tsf; + struct dentry *dentry_txstat; + + struct bcm43xx_private *bcm; + + /* saved xmitstatus. */ + struct bcm43xx_xmitstatus *xmitstatus_buffer; + int xmitstatus_ptr; + int xmitstatus_cnt; + /* We need a seperate buffer while printing to avoid + * concurrency issues. (New xmitstatus can arrive + * while we are printing). + */ + struct bcm43xx_xmitstatus *xmitstatus_print_buffer; + int saved_xmitstatus_ptr; + int saved_xmitstatus_cnt; + int xmitstatus_printing; +}; + +struct bcm43xx_debugfs { + struct dentry *root; + struct dentry *dentry_driverinfo; +}; + +void bcm43xx_debugfs_init(void); +void bcm43xx_debugfs_exit(void); +void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm); +void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm); +void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status); + +/* Debug helper: Dump binary data through printk. */ +void bcm43xx_printk_dump(const char *data, + size_t size, + const char *description); +/* Debug helper: Dump bitwise binary data through printk. */ +void bcm43xx_printk_bitdump(const unsigned char *data, + size_t bytes, int msb_to_lsb, + const char *description); +#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) \ + do { \ + bcm43xx_printk_bitdump((const unsigned char *)(pointer), \ + sizeof(*(pointer)), \ + (msb_to_lsb), \ + (description)); \ + } while (0) + +#else /* CONFIG_BCM43XX_DEBUG*/ + +static inline +void bcm43xx_debugfs_init(void) { } +static inline +void bcm43xx_debugfs_exit(void) { } +static inline +void bcm43xx_debugfs_add_device(struct bcm43xx_private *bcm) { } +static inline +void bcm43xx_debugfs_remove_device(struct bcm43xx_private *bcm) { } +static inline +void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) { } + +static inline +void bcm43xx_printk_dump(const char *data, + size_t size, + const char *description) +{ +} +static inline +void bcm43xx_printk_bitdump(const unsigned char *data, + size_t bytes, int msb_to_lsb, + const char *description) +{ +} +#define bcm43xx_printk_bitdumpt(pointer, msb_to_lsb, description) do { /* nothing */ } while (0) + +#endif /* CONFIG_BCM43XX_DEBUG*/ + +/* Ugly helper macros to make incomplete code more verbose on runtime */ +#ifdef TODO +# undef TODO +#endif +#define TODO() \ + do { \ + printk(KERN_INFO PFX "TODO: Incomplete code in %s() at %s:%d\n", \ + __FUNCTION__, __FILE__, __LINE__); \ + } while (0) + +#ifdef FIXME +# undef FIXME +#endif +#define FIXME() \ + do { \ + printk(KERN_INFO PFX "FIXME: Possibly broken code in %s() at %s:%d\n", \ + __FUNCTION__, __FILE__, __LINE__); \ + } while (0) + +#endif /* BCM43xx_DEBUGFS_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c new file mode 100644 index 00000000000..df19fbfa9ea --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -0,0 +1,1009 @@ +/* + + Broadcom BCM43xx wireless driver + + DMA ringbuffer and descriptor allocation/management + + Copyright (c) 2005 Michael Buesch + + Some code in this file is derived from the b44.c driver + Copyright (C) 2002 David S. Miller + Copyright (C) Pekka Pietikainen + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx.h" +#include "bcm43xx_dma.h" +#include "bcm43xx_main.h" +#include "bcm43xx_debugfs.h" +#include "bcm43xx_power.h" + +#include +#include +#include +#include +#include + + +static inline int free_slots(struct bcm43xx_dmaring *ring) +{ + return (ring->nr_slots - ring->used_slots); +} + +static inline int next_slot(struct bcm43xx_dmaring *ring, int slot) +{ + assert(slot >= -1 && slot <= ring->nr_slots - 1); + if (slot == ring->nr_slots - 1) + return 0; + return slot + 1; +} + +static inline int prev_slot(struct bcm43xx_dmaring *ring, int slot) +{ + assert(slot >= 0 && slot <= ring->nr_slots - 1); + if (slot == 0) + return ring->nr_slots - 1; + return slot - 1; +} + +/* Request a slot for usage. */ +static inline +int request_slot(struct bcm43xx_dmaring *ring) +{ + int slot; + + assert(ring->tx); + assert(!ring->suspended); + assert(free_slots(ring) != 0); + + slot = next_slot(ring, ring->current_slot); + ring->current_slot = slot; + ring->used_slots++; + + /* Check the number of available slots and suspend TX, + * if we are running low on free slots. + */ + if (unlikely(free_slots(ring) < ring->suspend_mark)) { + netif_stop_queue(ring->bcm->net_dev); + ring->suspended = 1; + } +#ifdef CONFIG_BCM43XX_DEBUG + if (ring->used_slots > ring->max_used_slots) + ring->max_used_slots = ring->used_slots; +#endif /* CONFIG_BCM43XX_DEBUG*/ + + return slot; +} + +/* Return a slot to the free slots. */ +static inline +void return_slot(struct bcm43xx_dmaring *ring, int slot) +{ + assert(ring->tx); + + ring->used_slots--; + + /* Check if TX is suspended and check if we have + * enough free slots to resume it again. + */ + if (unlikely(ring->suspended)) { + if (free_slots(ring) >= ring->resume_mark) { + ring->suspended = 0; + netif_wake_queue(ring->bcm->net_dev); + } + } +} + +static inline +dma_addr_t map_descbuffer(struct bcm43xx_dmaring *ring, + unsigned char *buf, + size_t len, + int tx) +{ + dma_addr_t dmaaddr; + + if (tx) { + dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, + buf, len, + DMA_TO_DEVICE); + } else { + dmaaddr = dma_map_single(&ring->bcm->pci_dev->dev, + buf, len, + DMA_FROM_DEVICE); + } + + return dmaaddr; +} + +static inline +void unmap_descbuffer(struct bcm43xx_dmaring *ring, + dma_addr_t addr, + size_t len, + int tx) +{ + if (tx) { + dma_unmap_single(&ring->bcm->pci_dev->dev, + addr, len, + DMA_TO_DEVICE); + } else { + dma_unmap_single(&ring->bcm->pci_dev->dev, + addr, len, + DMA_FROM_DEVICE); + } +} + +static inline +void sync_descbuffer_for_cpu(struct bcm43xx_dmaring *ring, + dma_addr_t addr, + size_t len) +{ + assert(!ring->tx); + + dma_sync_single_for_cpu(&ring->bcm->pci_dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +static inline +void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring, + dma_addr_t addr, + size_t len) +{ + assert(!ring->tx); + + dma_sync_single_for_device(&ring->bcm->pci_dev->dev, + addr, len, DMA_FROM_DEVICE); +} + +static inline +void mark_skb_mustfree(struct sk_buff *skb, + char mustfree) +{ + skb->cb[0] = mustfree; +} + +static inline +int skb_mustfree(struct sk_buff *skb) +{ + return (skb->cb[0] != 0); +} + +/* Unmap and free a descriptor buffer. */ +static inline +void free_descriptor_buffer(struct bcm43xx_dmaring *ring, + struct bcm43xx_dmadesc *desc, + struct bcm43xx_dmadesc_meta *meta, + int irq_context) +{ + assert(meta->skb); + if (skb_mustfree(meta->skb)) { + if (irq_context) + dev_kfree_skb_irq(meta->skb); + else + dev_kfree_skb(meta->skb); + } + meta->skb = NULL; + if (meta->txb) { + ieee80211_txb_free(meta->txb); + meta->txb = NULL; + } +} + +static int alloc_ringmemory(struct bcm43xx_dmaring *ring) +{ + struct device *dev = &(ring->bcm->pci_dev->dev); + + ring->vbase = dma_alloc_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, + &(ring->dmabase), GFP_KERNEL); + if (!ring->vbase) { + printk(KERN_ERR PFX "DMA ringmemory allocation failed\n"); + return -ENOMEM; + } + if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) { + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G\n"); + dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, + ring->vbase, ring->dmabase); + return -ENOMEM; + } + assert(!(ring->dmabase & 0x000003FF)); + memset(ring->vbase, 0, BCM43xx_DMA_RINGMEMSIZE); + + return 0; +} + +static void free_ringmemory(struct bcm43xx_dmaring *ring) +{ + struct device *dev = &(ring->bcm->pci_dev->dev); + + dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, + ring->vbase, ring->dmabase); +} + +/* Reset the RX DMA channel */ +int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, + u16 mmio_base) +{ + int i; + u32 value; + + bcm43xx_write32(bcm, + mmio_base + BCM43xx_DMA_RX_CONTROL, + 0x00000000); + for (i = 0; i < 1000; i++) { + value = bcm43xx_read32(bcm, + mmio_base + BCM43xx_DMA_RX_STATUS); + value &= BCM43xx_DMA_RXSTAT_STAT_MASK; + if (value == BCM43xx_DMA_RXSTAT_STAT_DISABLED) { + i = -1; + break; + } + udelay(10); + } + if (i != -1) { + printk(KERN_ERR PFX "Error: Wait on DMA RX status timed out.\n"); + return -ENODEV; + } + + return 0; +} + +static inline int dmacontroller_rx_reset(struct bcm43xx_dmaring *ring) +{ + assert(!ring->tx); + + return bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base); +} + +/* Reset the RX DMA channel */ +int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, + u16 mmio_base) +{ + int i; + u32 value; + + for (i = 0; i < 1000; i++) { + value = bcm43xx_read32(bcm, + mmio_base + BCM43xx_DMA_TX_STATUS); + value &= BCM43xx_DMA_TXSTAT_STAT_MASK; + if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED || + value == BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT || + value == BCM43xx_DMA_TXSTAT_STAT_STOPPED) + break; + udelay(10); + } + bcm43xx_write32(bcm, + mmio_base + BCM43xx_DMA_TX_CONTROL, + 0x00000000); + for (i = 0; i < 1000; i++) { + value = bcm43xx_read32(bcm, + mmio_base + BCM43xx_DMA_TX_STATUS); + value &= BCM43xx_DMA_TXSTAT_STAT_MASK; + if (value == BCM43xx_DMA_TXSTAT_STAT_DISABLED) { + i = -1; + break; + } + udelay(10); + } + if (i != -1) { + printk(KERN_ERR PFX "Error: Wait on DMA TX status timed out.\n"); + return -ENODEV; + } + /* ensure the reset is completed. */ + udelay(300); + + return 0; +} + +static inline int dmacontroller_tx_reset(struct bcm43xx_dmaring *ring) +{ + assert(ring->tx); + + return bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base); +} + +static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, + struct bcm43xx_dmadesc *desc, + struct bcm43xx_dmadesc_meta *meta, + gfp_t gfp_flags) +{ + struct bcm43xx_rxhdr *rxhdr; + dma_addr_t dmaaddr; + u32 desc_addr; + u32 desc_ctl; + const int slot = (int)(desc - ring->vbase); + struct sk_buff *skb; + + assert(slot >= 0 && slot < ring->nr_slots); + assert(!ring->tx); + + skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags); + if (unlikely(!skb)) + return -ENOMEM; + dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0); + if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) { + unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); + dev_kfree_skb_any(skb); + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G\n"); + return -ENOMEM; + } + meta->skb = skb; + meta->dmaaddr = dmaaddr; + skb->dev = ring->bcm->net_dev; + mark_skb_mustfree(skb, 1); + desc_addr = (u32)(dmaaddr + ring->memoffset); + desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK & + (u32)(ring->rx_buffersize - ring->frameoffset)); + if (slot == ring->nr_slots - 1) + desc_ctl |= BCM43xx_DMADTOR_DTABLEEND; + set_desc_addr(desc, desc_addr); + set_desc_ctl(desc, desc_ctl); + + rxhdr = (struct bcm43xx_rxhdr *)(skb->data); + rxhdr->frame_length = 0; + rxhdr->flags1 = 0; + + return 0; +} + +/* Allocate the initial descbuffers. + * This is used for an RX ring only. + */ +static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring) +{ + int i, err = -ENOMEM; + struct bcm43xx_dmadesc *desc = NULL; + struct bcm43xx_dmadesc_meta *meta; + + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->vbase + i; + meta = ring->meta + i; + + err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); + if (err) + goto err_unwind; + + assert(ring->used_slots <= ring->nr_slots); + } + ring->used_slots = ring->nr_slots; + + err = 0; +out: + return err; + +err_unwind: + for ( ; i >= 0; i--) { + desc = ring->vbase + i; + meta = ring->meta + i; + + unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); + dev_kfree_skb(meta->skb); + } + ring->used_slots = 0; + goto out; +} + +/* Do initial setup of the DMA controller. + * Reset the controller, write the ring busaddress + * and switch the "enable" bit on. + */ +static int dmacontroller_setup(struct bcm43xx_dmaring *ring) +{ + int err = 0; + u32 value; + + if (ring->tx) { + /* Set Transmit Control register to "transmit enable" */ + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_TX_CONTROL, + BCM43xx_DMA_TXCTRL_ENABLE); + /* Set Transmit Descriptor ring address. */ + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_TX_DESC_RING, + ring->dmabase + ring->memoffset); + } else { + err = alloc_initial_descbuffers(ring); + if (err) + goto out; + /* Set Receive Control "receive enable" and frame offset */ + value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT); + value |= BCM43xx_DMA_RXCTRL_ENABLE; + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_RX_CONTROL, + value); + /* Set Receive Descriptor ring address. */ + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_RX_DESC_RING, + ring->dmabase + ring->memoffset); + /* Init the descriptor pointer. */ + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_RX_DESC_INDEX, + 200); + } + +out: + return err; +} + +/* Shutdown the DMA controller. */ +static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring) +{ + if (ring->tx) { + dmacontroller_tx_reset(ring); + /* Zero out Transmit Descriptor ring address. */ + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_TX_DESC_RING, + 0x00000000); + } else { + dmacontroller_rx_reset(ring); + /* Zero out Receive Descriptor ring address. */ + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_RX_DESC_RING, + 0x00000000); + } +} + +static void free_all_descbuffers(struct bcm43xx_dmaring *ring) +{ + struct bcm43xx_dmadesc *desc; + struct bcm43xx_dmadesc_meta *meta; + int i; + + if (!ring->used_slots) + return; + for (i = 0; i < ring->nr_slots; i++) { + desc = ring->vbase + i; + meta = ring->meta + i; + + if (!meta->skb) { + assert(ring->tx); + assert(!meta->txb); + continue; + } + if (ring->tx) { + unmap_descbuffer(ring, meta->dmaaddr, + meta->skb->len, 1); + } else { + unmap_descbuffer(ring, meta->dmaaddr, + ring->rx_buffersize, 0); + } + free_descriptor_buffer(ring, desc, meta, 0); + } +} + +/* Main initialization function. */ +static +struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm, + u16 dma_controller_base, + int nr_descriptor_slots, + int tx) +{ + struct bcm43xx_dmaring *ring; + int err; + + ring = kzalloc(sizeof(*ring), GFP_KERNEL); + if (!ring) + goto out; + + ring->meta = kzalloc(sizeof(*ring->meta) * nr_descriptor_slots, + GFP_KERNEL); + if (!ring->meta) + goto err_kfree_ring; + + ring->memoffset = BCM43xx_DMA_DMABUSADDROFFSET; +#ifdef CONFIG_BCM947XX + if (bcm->pci_dev->bus->number == 0) + ring->memoffset = 0; +#endif + + + spin_lock_init(&ring->lock); + ring->bcm = bcm; + ring->nr_slots = nr_descriptor_slots; + ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100; + ring->resume_mark = ring->nr_slots * BCM43xx_TXRESUME_PERCENT / 100; + assert(ring->suspend_mark < ring->resume_mark); + ring->mmio_base = dma_controller_base; + if (tx) { + ring->tx = 1; + ring->current_slot = -1; + } else { + switch (dma_controller_base) { + case BCM43xx_MMIO_DMA1_BASE: + ring->rx_buffersize = BCM43xx_DMA1_RXBUFFERSIZE; + ring->frameoffset = BCM43xx_DMA1_RX_FRAMEOFFSET; + break; + case BCM43xx_MMIO_DMA4_BASE: + ring->rx_buffersize = BCM43xx_DMA4_RXBUFFERSIZE; + ring->frameoffset = BCM43xx_DMA4_RX_FRAMEOFFSET; + break; + default: + assert(0); + } + } + + err = alloc_ringmemory(ring); + if (err) + goto err_kfree_meta; + err = dmacontroller_setup(ring); + if (err) + goto err_free_ringmemory; + +out: + return ring; + +err_free_ringmemory: + free_ringmemory(ring); +err_kfree_meta: + kfree(ring->meta); +err_kfree_ring: + kfree(ring); + ring = NULL; + goto out; +} + +/* Main cleanup function. */ +static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring) +{ + if (!ring) + return; + + dprintk(KERN_INFO PFX "DMA 0x%04x (%s) max used slots: %d/%d\n", + ring->mmio_base, + (ring->tx) ? "TX" : "RX", + ring->max_used_slots, ring->nr_slots); + /* Device IRQs are disabled prior entering this function, + * so no need to take care of concurrency with rx handler stuff. + */ + dmacontroller_cleanup(ring); + free_all_descbuffers(ring); + free_ringmemory(ring); + + kfree(ring->meta); + kfree(ring); +} + +void bcm43xx_dma_free(struct bcm43xx_private *bcm) +{ + bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring1); + bcm->current_core->dma->rx_ring1 = NULL; + bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring0); + bcm->current_core->dma->rx_ring0 = NULL; + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring3); + bcm->current_core->dma->tx_ring3 = NULL; + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring2); + bcm->current_core->dma->tx_ring2 = NULL; + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring1); + bcm->current_core->dma->tx_ring1 = NULL; + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring0); + bcm->current_core->dma->tx_ring0 = NULL; +} + +int bcm43xx_dma_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_dmaring *ring; + int err = -ENOMEM; + + /* setup TX DMA channels. */ + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE, + BCM43xx_TXRING_SLOTS, 1); + if (!ring) + goto out; + bcm->current_core->dma->tx_ring0 = ring; + + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE, + BCM43xx_TXRING_SLOTS, 1); + if (!ring) + goto err_destroy_tx0; + bcm->current_core->dma->tx_ring1 = ring; + + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE, + BCM43xx_TXRING_SLOTS, 1); + if (!ring) + goto err_destroy_tx1; + bcm->current_core->dma->tx_ring2 = ring; + + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, + BCM43xx_TXRING_SLOTS, 1); + if (!ring) + goto err_destroy_tx2; + bcm->current_core->dma->tx_ring3 = ring; + + /* setup RX DMA channels. */ + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE, + BCM43xx_RXRING_SLOTS, 0); + if (!ring) + goto err_destroy_tx3; + bcm->current_core->dma->rx_ring0 = ring; + + if (bcm->current_core->rev < 5) { + ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, + BCM43xx_RXRING_SLOTS, 0); + if (!ring) + goto err_destroy_rx0; + bcm->current_core->dma->rx_ring1 = ring; + } + + dprintk(KERN_INFO PFX "DMA initialized\n"); + err = 0; +out: + return err; + +err_destroy_rx0: + bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring0); + bcm->current_core->dma->rx_ring0 = NULL; +err_destroy_tx3: + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring3); + bcm->current_core->dma->tx_ring3 = NULL; +err_destroy_tx2: + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring2); + bcm->current_core->dma->tx_ring2 = NULL; +err_destroy_tx1: + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring1); + bcm->current_core->dma->tx_ring1 = NULL; +err_destroy_tx0: + bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring0); + bcm->current_core->dma->tx_ring0 = NULL; + goto out; +} + +/* Generate a cookie for the TX header. */ +static inline +u16 generate_cookie(struct bcm43xx_dmaring *ring, + int slot) +{ + u16 cookie = 0x0000; + + /* Use the upper 4 bits of the cookie as + * DMA controller ID and store the slot number + * in the lower 12 bits + */ + switch (ring->mmio_base) { + default: + assert(0); + case BCM43xx_MMIO_DMA1_BASE: + break; + case BCM43xx_MMIO_DMA2_BASE: + cookie = 0x1000; + break; + case BCM43xx_MMIO_DMA3_BASE: + cookie = 0x2000; + break; + case BCM43xx_MMIO_DMA4_BASE: + cookie = 0x3000; + break; + } + assert(((u16)slot & 0xF000) == 0x0000); + cookie |= (u16)slot; + + return cookie; +} + +/* Inspect a cookie and find out to which controller/slot it belongs. */ +static inline +struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm, + u16 cookie, int *slot) +{ + struct bcm43xx_dmaring *ring = NULL; + + switch (cookie & 0xF000) { + case 0x0000: + ring = bcm->current_core->dma->tx_ring0; + break; + case 0x1000: + ring = bcm->current_core->dma->tx_ring1; + break; + case 0x2000: + ring = bcm->current_core->dma->tx_ring2; + break; + case 0x3000: + ring = bcm->current_core->dma->tx_ring3; + break; + default: + assert(0); + } + *slot = (cookie & 0x0FFF); + assert(*slot >= 0 && *slot < ring->nr_slots); + + return ring; +} + +static inline void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, + int slot) +{ + /* Everything is ready to start. Buffers are DMA mapped and + * associated with slots. + * "slot" is the last slot of the new frame we want to transmit. + * Close your seat belts now, please. + */ + wmb(); + slot = next_slot(ring, slot); + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_TX_DESC_INDEX, + (u32)(slot * sizeof(struct bcm43xx_dmadesc))); +} + +static inline +int dma_tx_fragment(struct bcm43xx_dmaring *ring, + struct sk_buff *skb, + struct ieee80211_txb *txb, + u8 cur_frag) +{ + int slot; + struct bcm43xx_dmadesc *desc; + struct bcm43xx_dmadesc_meta *meta; + u32 desc_ctl; + u32 desc_addr; + + assert(skb_shinfo(skb)->nr_frags == 0); + + slot = request_slot(ring); + desc = ring->vbase + slot; + meta = ring->meta + slot; + + if (cur_frag == 0) { + /* Save the txb pointer for freeing in xmitstatus IRQ */ + meta->txb = txb; + } + + /* Add a device specific TX header. */ + assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); + /* Reserve enough headroom for the device tx header. */ + __skb_push(skb, sizeof(struct bcm43xx_txhdr)); + /* Now calculate and add the tx header. + * The tx header includes the PLCP header. + */ + bcm43xx_generate_txhdr(ring->bcm, + (struct bcm43xx_txhdr *)skb->data, + skb->data + sizeof(struct bcm43xx_txhdr), + skb->len - sizeof(struct bcm43xx_txhdr), + (cur_frag == 0), + generate_cookie(ring, slot)); + + meta->skb = skb; + meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); + if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) { + return_slot(ring, slot); + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G\n"); + return -ENOMEM; + } + + desc_addr = (u32)(meta->dmaaddr + ring->memoffset); + desc_ctl = BCM43xx_DMADTOR_FRAMESTART | BCM43xx_DMADTOR_FRAMEEND; + desc_ctl |= BCM43xx_DMADTOR_COMPIRQ; + desc_ctl |= (BCM43xx_DMADTOR_BYTECNT_MASK & + (u32)(meta->skb->len - ring->frameoffset)); + if (slot == ring->nr_slots - 1) + desc_ctl |= BCM43xx_DMADTOR_DTABLEEND; + + set_desc_ctl(desc, desc_ctl); + set_desc_addr(desc, desc_addr); + /* Now transfer the whole frame. */ + dmacontroller_poke_tx(ring, slot); + + return 0; +} + +static inline int dma_transfer_txb(struct bcm43xx_dmaring *ring, + struct ieee80211_txb *txb) +{ + /* We just received a packet from the kernel network subsystem. + * Add headers and DMA map the memory. Poke + * the device to send the stuff. + * Note that this is called from atomic context. + */ + u8 i; + struct sk_buff *skb; + + assert(ring->tx); + if (unlikely(free_slots(ring) < txb->nr_frags)) { + /* The queue should be stopped, + * if we are low on free slots. + * If this ever triggers, we have to lower the suspend_mark. + */ + dprintkl(KERN_ERR PFX "Out of DMA descriptor slots!\n"); + return -ENOMEM; + } + + assert(irqs_disabled()); + spin_lock(&ring->lock); + for (i = 0; i < txb->nr_frags; i++) { + skb = txb->fragments[i]; + /* We do not free the skb, as it is freed as + * part of the txb freeing. + */ + mark_skb_mustfree(skb, 0); + dma_tx_fragment(ring, skb, txb, i); + //TODO: handle failure of dma_tx_fragment + } + spin_unlock(&ring->lock); + + return 0; +} + +int fastcall +bcm43xx_dma_transfer_txb(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + return dma_transfer_txb(bcm->current_core->dma->tx_ring1, + txb); +} + +void fastcall +bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ + struct bcm43xx_dmaring *ring; + struct bcm43xx_dmadesc *desc; + struct bcm43xx_dmadesc_meta *meta; + int is_last_fragment; + int slot; + + ring = parse_cookie(bcm, status->cookie, &slot); + assert(ring); + assert(ring->tx); + assert(irqs_disabled()); + spin_lock(&ring->lock); + + assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART); + while (1) { + assert(slot >= 0 && slot < ring->nr_slots); + desc = ring->vbase + slot; + meta = ring->meta + slot; + + is_last_fragment = !!(get_desc_ctl(desc) & BCM43xx_DMADTOR_FRAMEEND); + unmap_descbuffer(ring, meta->dmaaddr, meta->skb->len, 1); + free_descriptor_buffer(ring, desc, meta, 1); + /* Everything belonging to the slot is unmapped + * and freed, so we can return it. + */ + return_slot(ring, slot); + + if (is_last_fragment) + break; + slot = next_slot(ring, slot); + } + bcm->stats.last_tx = jiffies; + + spin_unlock(&ring->lock); +} + +static inline +void dma_rx(struct bcm43xx_dmaring *ring, + int *slot) +{ + struct bcm43xx_dmadesc *desc; + struct bcm43xx_dmadesc_meta *meta; + struct bcm43xx_rxhdr *rxhdr; + struct sk_buff *skb; + u16 len; + int err; + dma_addr_t dmaaddr; + + desc = ring->vbase + *slot; + meta = ring->meta + *slot; + + sync_descbuffer_for_cpu(ring, meta->dmaaddr, ring->rx_buffersize); + skb = meta->skb; + + if (ring->mmio_base == BCM43xx_MMIO_DMA4_BASE) { + /* We received an xmit status. */ + struct bcm43xx_hwxmitstatus *hw = (struct bcm43xx_hwxmitstatus *)skb->data; + struct bcm43xx_xmitstatus stat; + + stat.cookie = le16_to_cpu(hw->cookie); + stat.flags = hw->flags; + stat.cnt1 = hw->cnt1; + stat.cnt2 = hw->cnt2; + stat.seq = le16_to_cpu(hw->seq); + stat.unknown = le16_to_cpu(hw->unknown); + + bcm43xx_debugfs_log_txstat(ring->bcm, &stat); + bcm43xx_dma_handle_xmitstatus(ring->bcm, &stat); + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, ring->rx_buffersize); + + return; + } + rxhdr = (struct bcm43xx_rxhdr *)skb->data; + len = le16_to_cpu(rxhdr->frame_length); + if (len == 0) { + int i = 0; + + do { + udelay(2); + barrier(); + len = le16_to_cpu(rxhdr->frame_length); + } while (len == 0 && i++ < 5); + if (len == 0) + goto drop; + } + if (unlikely(len > ring->rx_buffersize)) { + /* The data did not fit into one descriptor buffer + * and is split over multiple buffers. + * This should never happen, as we try to allocate buffers + * big enough. So simply ignore this packet. + */ + int cnt = 1; + s32 tmp = len - ring->rx_buffersize; + + for ( ; tmp > 0; tmp -= ring->rx_buffersize) { + *slot = next_slot(ring, *slot); + cnt++; + } + printkl(KERN_ERR PFX "DMA RX buffer too small. %d dropped.\n", + cnt); + goto drop; + } + len -= IEEE80211_FCS_LEN; + + dmaaddr = meta->dmaaddr; + err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); + if (unlikely(err)) { + dprintkl(KERN_ERR PFX "DMA RX: setup_rx_descbuffer() failed\n"); + goto drop; + } + + unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); + skb_put(skb, len + ring->frameoffset); + skb_pull(skb, ring->frameoffset); + + err = bcm43xx_rx(ring->bcm, skb, rxhdr); + if (err) { + dev_kfree_skb_irq(skb); + goto drop; + } + +drop: + return; +} + +void fastcall +bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) +{ + u32 status; + u16 descptr; + int slot, current_slot; +#ifdef CONFIG_BCM43XX_DEBUG + int used_slots = 0; +#endif + + assert(!ring->tx); + assert(irqs_disabled()); + spin_lock(&ring->lock); + + status = bcm43xx_read32(ring->bcm, ring->mmio_base + BCM43xx_DMA_RX_STATUS); + descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK); + current_slot = descptr / sizeof(struct bcm43xx_dmadesc); + assert(current_slot >= 0 && current_slot < ring->nr_slots); + + slot = ring->current_slot; + for ( ; slot != current_slot; slot = next_slot(ring, slot)) { + dma_rx(ring, &slot); +#ifdef CONFIG_BCM43XX_DEBUG + if (++used_slots > ring->max_used_slots) + ring->max_used_slots = used_slots; +#endif + } + bcm43xx_write32(ring->bcm, + ring->mmio_base + BCM43xx_DMA_RX_DESC_INDEX, + (u32)(slot * sizeof(struct bcm43xx_dmadesc))); + ring->current_slot = slot; + + spin_unlock(&ring->lock); +} + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h new file mode 100644 index 00000000000..e32cf68f8e1 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -0,0 +1,176 @@ +#ifndef BCM43xx_DMA_H_ +#define BCM43xx_DMA_H_ + +#include +#include +#include +#include +#include + + +/* DMA-Interrupt reasons. */ +/*TODO: add the missing ones. */ +#define BCM43xx_DMAIRQ_ERR0 (1 << 10) +#define BCM43xx_DMAIRQ_ERR1 (1 << 11) +#define BCM43xx_DMAIRQ_ERR2 (1 << 12) +#define BCM43xx_DMAIRQ_ERR3 (1 << 13) +#define BCM43xx_DMAIRQ_ERR4 (1 << 14) +#define BCM43xx_DMAIRQ_ERR5 (1 << 15) +#define BCM43xx_DMAIRQ_RX_DONE (1 << 16) +/* helpers */ +#define BCM43xx_DMAIRQ_ANYERR (BCM43xx_DMAIRQ_ERR0 | \ + BCM43xx_DMAIRQ_ERR1 | \ + BCM43xx_DMAIRQ_ERR2 | \ + BCM43xx_DMAIRQ_ERR3 | \ + BCM43xx_DMAIRQ_ERR4 | \ + BCM43xx_DMAIRQ_ERR5) +#define BCM43xx_DMAIRQ_FATALERR (BCM43xx_DMAIRQ_ERR0 | \ + BCM43xx_DMAIRQ_ERR1 | \ + BCM43xx_DMAIRQ_ERR2 | \ + BCM43xx_DMAIRQ_ERR4 | \ + BCM43xx_DMAIRQ_ERR5) +#define BCM43xx_DMAIRQ_NONFATALERR BCM43xx_DMAIRQ_ERR3 + +/* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */ +#define BCM43xx_DMA_TX_CONTROL 0x00 +#define BCM43xx_DMA_TX_DESC_RING 0x04 +#define BCM43xx_DMA_TX_DESC_INDEX 0x08 +#define BCM43xx_DMA_TX_STATUS 0x0c +#define BCM43xx_DMA_RX_CONTROL 0x10 +#define BCM43xx_DMA_RX_DESC_RING 0x14 +#define BCM43xx_DMA_RX_DESC_INDEX 0x18 +#define BCM43xx_DMA_RX_STATUS 0x1c + +/* DMA controller channel control word values. */ +#define BCM43xx_DMA_TXCTRL_ENABLE (1 << 0) +#define BCM43xx_DMA_TXCTRL_SUSPEND (1 << 1) +#define BCM43xx_DMA_TXCTRL_LOOPBACK (1 << 2) +#define BCM43xx_DMA_TXCTRL_FLUSH (1 << 4) +#define BCM43xx_DMA_RXCTRL_ENABLE (1 << 0) +#define BCM43xx_DMA_RXCTRL_FRAMEOFF_MASK 0x000000fe +#define BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT 1 +#define BCM43xx_DMA_RXCTRL_PIO (1 << 8) +/* DMA controller channel status word values. */ +#define BCM43xx_DMA_TXSTAT_DPTR_MASK 0x00000fff +#define BCM43xx_DMA_TXSTAT_STAT_MASK 0x0000f000 +#define BCM43xx_DMA_TXSTAT_STAT_DISABLED 0x00000000 +#define BCM43xx_DMA_TXSTAT_STAT_ACTIVE 0x00001000 +#define BCM43xx_DMA_TXSTAT_STAT_IDLEWAIT 0x00002000 +#define BCM43xx_DMA_TXSTAT_STAT_STOPPED 0x00003000 +#define BCM43xx_DMA_TXSTAT_STAT_SUSP 0x00004000 +#define BCM43xx_DMA_TXSTAT_ERROR_MASK 0x000f0000 +#define BCM43xx_DMA_TXSTAT_FLUSHED (1 << 20) +#define BCM43xx_DMA_RXSTAT_DPTR_MASK 0x00000fff +#define BCM43xx_DMA_RXSTAT_STAT_MASK 0x0000f000 +#define BCM43xx_DMA_RXSTAT_STAT_DISABLED 0x00000000 +#define BCM43xx_DMA_RXSTAT_STAT_ACTIVE 0x00001000 +#define BCM43xx_DMA_RXSTAT_STAT_IDLEWAIT 0x00002000 +#define BCM43xx_DMA_RXSTAT_STAT_RESERVED 0x00003000 +#define BCM43xx_DMA_RXSTAT_STAT_ERRORS 0x00004000 +#define BCM43xx_DMA_RXSTAT_ERROR_MASK 0x000f0000 + +/* DMA descriptor control field values. */ +#define BCM43xx_DMADTOR_BYTECNT_MASK 0x00001fff +#define BCM43xx_DMADTOR_DTABLEEND (1 << 28) /* End of descriptor table */ +#define BCM43xx_DMADTOR_COMPIRQ (1 << 29) /* IRQ on completion request */ +#define BCM43xx_DMADTOR_FRAMEEND (1 << 30) +#define BCM43xx_DMADTOR_FRAMESTART (1 << 31) + +/* Misc DMA constants */ +#define BCM43xx_DMA_RINGMEMSIZE PAGE_SIZE +#define BCM43xx_DMA_BUSADDRMAX 0x3FFFFFFF +#define BCM43xx_DMA_DMABUSADDROFFSET (1 << 30) +#define BCM43xx_DMA1_RX_FRAMEOFFSET 30 +#define BCM43xx_DMA4_RX_FRAMEOFFSET 0 + +/* DMA engine tuning knobs */ +#define BCM43xx_TXRING_SLOTS 512 +#define BCM43xx_RXRING_SLOTS 64 +#define BCM43xx_DMA1_RXBUFFERSIZE (2304 + 100) +#define BCM43xx_DMA4_RXBUFFERSIZE 16 +/* Suspend the tx queue, if less than this percent slots are free. */ +#define BCM43xx_TXSUSPEND_PERCENT 20 +/* Resume the tx queue, if more than this percent slots are free. */ +#define BCM43xx_TXRESUME_PERCENT 50 + + +struct sk_buff; +struct bcm43xx_private; +struct bcm43xx_xmitstatus; + + +struct bcm43xx_dmadesc { + __le32 _control; + __le32 _address; +} __attribute__((__packed__)); + +/* Macros to access the bcm43xx_dmadesc struct */ +#define get_desc_ctl(desc) le32_to_cpu((desc)->_control) +#define set_desc_ctl(desc, ctl) do { (desc)->_control = cpu_to_le32(ctl); } while (0) +#define get_desc_addr(desc) le32_to_cpu((desc)->_address) +#define set_desc_addr(desc, addr) do { (desc)->_address = cpu_to_le32(addr); } while (0) + +struct bcm43xx_dmadesc_meta { + /* The kernel DMA-able buffer. */ + struct sk_buff *skb; + /* DMA base bus-address of the descriptor buffer. */ + dma_addr_t dmaaddr; + /* Pointer to our txb (can be NULL). + * This should be freed in completion IRQ. + */ + struct ieee80211_txb *txb; +}; + +struct bcm43xx_dmaring { + spinlock_t lock; + struct bcm43xx_private *bcm; + /* Kernel virtual base address of the ring memory. */ + struct bcm43xx_dmadesc *vbase; + /* DMA memory offset */ + dma_addr_t memoffset; + /* (Unadjusted) DMA base bus-address of the ring memory. */ + dma_addr_t dmabase; + /* Meta data about all descriptors. */ + struct bcm43xx_dmadesc_meta *meta; + /* Number of descriptor slots in the ring. */ + int nr_slots; + /* Number of used descriptor slots. */ + int used_slots; + /* Currently used slot in the ring. */ + int current_slot; + /* Marks to suspend/resume the queue. */ + int suspend_mark; + int resume_mark; + /* Frameoffset in octets. */ + u32 frameoffset; + /* Descriptor buffer size. */ + u16 rx_buffersize; + /* The MMIO base register of the DMA controller, this + * ring is posted to. + */ + u16 mmio_base; + u8 tx:1, /* TRUE, if this is a TX ring. */ + suspended:1; /* TRUE, if transfers are suspended on this ring. */ +#ifdef CONFIG_BCM43XX_DEBUG + /* Maximum number of used slots. */ + int max_used_slots; +#endif /* CONFIG_BCM43XX_DEBUG*/ +}; + + +int bcm43xx_dma_init(struct bcm43xx_private *bcm); +void bcm43xx_dma_free(struct bcm43xx_private *bcm); + +int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, + u16 dmacontroller_mmio_base); +int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, + u16 dmacontroller_mmio_base); + +int FASTCALL(bcm43xx_dma_transfer_txb(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb)); +void FASTCALL(bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status)); + +void FASTCALL(bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)); + +#endif /* BCM43xx_DMA_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c new file mode 100644 index 00000000000..22587e0e1a0 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c @@ -0,0 +1,367 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx.h" +#include "bcm43xx_ilt.h" +#include "bcm43xx_phy.h" + + +/**** Initial Internal Lookup Tables ****/ + +const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE] = { + 0xFEB93FFD, 0xFEC63FFD, /* 0 */ + 0xFED23FFD, 0xFEDF3FFD, + 0xFEEC3FFE, 0xFEF83FFE, + 0xFF053FFE, 0xFF113FFE, + 0xFF1E3FFE, 0xFF2A3FFF, /* 8 */ + 0xFF373FFF, 0xFF443FFF, + 0xFF503FFF, 0xFF5D3FFF, + 0xFF693FFF, 0xFF763FFF, + 0xFF824000, 0xFF8F4000, /* 16 */ + 0xFF9B4000, 0xFFA84000, + 0xFFB54000, 0xFFC14000, + 0xFFCE4000, 0xFFDA4000, + 0xFFE74000, 0xFFF34000, /* 24 */ + 0x00004000, 0x000D4000, + 0x00194000, 0x00264000, + 0x00324000, 0x003F4000, + 0x004B4000, 0x00584000, /* 32 */ + 0x00654000, 0x00714000, + 0x007E4000, 0x008A3FFF, + 0x00973FFF, 0x00A33FFF, + 0x00B03FFF, 0x00BC3FFF, /* 40 */ + 0x00C93FFF, 0x00D63FFF, + 0x00E23FFE, 0x00EF3FFE, + 0x00FB3FFE, 0x01083FFE, + 0x01143FFE, 0x01213FFD, /* 48 */ + 0x012E3FFD, 0x013A3FFD, + 0x01473FFD, +}; + +const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE] = { + 0xDB93CB87, 0xD666CF64, /* 0 */ + 0xD1FDD358, 0xCDA6D826, + 0xCA38DD9F, 0xC729E2B4, + 0xC469E88E, 0xC26AEE2B, + 0xC0DEF46C, 0xC073FA62, /* 8 */ + 0xC01D00D5, 0xC0760743, + 0xC1560D1E, 0xC2E51369, + 0xC4ED18FF, 0xC7AC1ED7, + 0xCB2823B2, 0xCEFA28D9, /* 16 */ + 0xD2F62D3F, 0xD7BB3197, + 0xDCE53568, 0xE1FE3875, + 0xE7D13B35, 0xED663D35, + 0xF39B3EC4, 0xF98E3FA7, /* 24 */ + 0x00004000, 0x06723FA7, + 0x0C653EC4, 0x129A3D35, + 0x182F3B35, 0x1E023875, + 0x231B3568, 0x28453197, /* 32 */ + 0x2D0A2D3F, 0x310628D9, + 0x34D823B2, 0x38541ED7, + 0x3B1318FF, 0x3D1B1369, + 0x3EAA0D1E, 0x3F8A0743, /* 40 */ + 0x3FE300D5, 0x3F8DFA62, + 0x3F22F46C, 0x3D96EE2B, + 0x3B97E88E, 0x38D7E2B4, + 0x35C8DD9F, 0x325AD826, /* 48 */ + 0x2E03D358, 0x299ACF64, + 0x246DCB87, +}; + +const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE] = { + 0x0082, 0x0082, 0x0102, 0x0182, /* 0 */ + 0x0202, 0x0282, 0x0302, 0x0382, + 0x0402, 0x0482, 0x0502, 0x0582, + 0x05E2, 0x0662, 0x06E2, 0x0762, + 0x07E2, 0x0842, 0x08C2, 0x0942, /* 16 */ + 0x09C2, 0x0A22, 0x0AA2, 0x0B02, + 0x0B82, 0x0BE2, 0x0C62, 0x0CC2, + 0x0D42, 0x0DA2, 0x0E02, 0x0E62, + 0x0EE2, 0x0F42, 0x0FA2, 0x1002, /* 32 */ + 0x1062, 0x10C2, 0x1122, 0x1182, + 0x11E2, 0x1242, 0x12A2, 0x12E2, + 0x1342, 0x13A2, 0x1402, 0x1442, + 0x14A2, 0x14E2, 0x1542, 0x1582, /* 48 */ + 0x15E2, 0x1622, 0x1662, 0x16C1, + 0x1701, 0x1741, 0x1781, 0x17E1, + 0x1821, 0x1861, 0x18A1, 0x18E1, + 0x1921, 0x1961, 0x19A1, 0x19E1, /* 64 */ + 0x1A21, 0x1A61, 0x1AA1, 0x1AC1, + 0x1B01, 0x1B41, 0x1B81, 0x1BA1, + 0x1BE1, 0x1C21, 0x1C41, 0x1C81, + 0x1CA1, 0x1CE1, 0x1D01, 0x1D41, /* 80 */ + 0x1D61, 0x1DA1, 0x1DC1, 0x1E01, + 0x1E21, 0x1E61, 0x1E81, 0x1EA1, + 0x1EE1, 0x1F01, 0x1F21, 0x1F41, + 0x1F81, 0x1FA1, 0x1FC1, 0x1FE1, /* 96 */ + 0x2001, 0x2041, 0x2061, 0x2081, + 0x20A1, 0x20C1, 0x20E1, 0x2101, + 0x2121, 0x2141, 0x2161, 0x2181, + 0x21A1, 0x21C1, 0x21E1, 0x2201, /* 112 */ + 0x2221, 0x2241, 0x2261, 0x2281, + 0x22A1, 0x22C1, 0x22C1, 0x22E1, + 0x2301, 0x2321, 0x2341, 0x2361, + 0x2361, 0x2381, 0x23A1, 0x23C1, /* 128 */ + 0x23E1, 0x23E1, 0x2401, 0x2421, + 0x2441, 0x2441, 0x2461, 0x2481, + 0x2481, 0x24A1, 0x24C1, 0x24C1, + 0x24E1, 0x2501, 0x2501, 0x2521, /* 144 */ + 0x2541, 0x2541, 0x2561, 0x2561, + 0x2581, 0x25A1, 0x25A1, 0x25C1, + 0x25C1, 0x25E1, 0x2601, 0x2601, + 0x2621, 0x2621, 0x2641, 0x2641, /* 160 */ + 0x2661, 0x2661, 0x2681, 0x2681, + 0x26A1, 0x26A1, 0x26C1, 0x26C1, + 0x26E1, 0x26E1, 0x2701, 0x2701, + 0x2721, 0x2721, 0x2740, 0x2740, /* 176 */ + 0x2760, 0x2760, 0x2780, 0x2780, + 0x2780, 0x27A0, 0x27A0, 0x27C0, + 0x27C0, 0x27E0, 0x27E0, 0x27E0, + 0x2800, 0x2800, 0x2820, 0x2820, /* 192 */ + 0x2820, 0x2840, 0x2840, 0x2840, + 0x2860, 0x2860, 0x2880, 0x2880, + 0x2880, 0x28A0, 0x28A0, 0x28A0, + 0x28C0, 0x28C0, 0x28C0, 0x28E0, /* 208 */ + 0x28E0, 0x28E0, 0x2900, 0x2900, + 0x2900, 0x2920, 0x2920, 0x2920, + 0x2940, 0x2940, 0x2940, 0x2960, + 0x2960, 0x2960, 0x2960, 0x2980, /* 224 */ + 0x2980, 0x2980, 0x29A0, 0x29A0, + 0x29A0, 0x29A0, 0x29C0, 0x29C0, + 0x29C0, 0x29E0, 0x29E0, 0x29E0, + 0x29E0, 0x2A00, 0x2A00, 0x2A00, /* 240 */ + 0x2A00, 0x2A20, 0x2A20, 0x2A20, + 0x2A20, 0x2A40, 0x2A40, 0x2A40, + 0x2A40, 0x2A60, 0x2A60, 0x2A60, +}; + +const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE] = { + 0x0089, 0x02E9, 0x0409, 0x04E9, /* 0 */ + 0x05A9, 0x0669, 0x0709, 0x0789, + 0x0829, 0x08A9, 0x0929, 0x0989, + 0x0A09, 0x0A69, 0x0AC9, 0x0B29, + 0x0BA9, 0x0BE9, 0x0C49, 0x0CA9, /* 16 */ + 0x0D09, 0x0D69, 0x0DA9, 0x0E09, + 0x0E69, 0x0EA9, 0x0F09, 0x0F49, + 0x0FA9, 0x0FE9, 0x1029, 0x1089, + 0x10C9, 0x1109, 0x1169, 0x11A9, /* 32 */ + 0x11E9, 0x1229, 0x1289, 0x12C9, + 0x1309, 0x1349, 0x1389, 0x13C9, + 0x1409, 0x1449, 0x14A9, 0x14E9, + 0x1529, 0x1569, 0x15A9, 0x15E9, /* 48 */ + 0x1629, 0x1669, 0x16A9, 0x16E8, + 0x1728, 0x1768, 0x17A8, 0x17E8, + 0x1828, 0x1868, 0x18A8, 0x18E8, + 0x1928, 0x1968, 0x19A8, 0x19E8, /* 64 */ + 0x1A28, 0x1A68, 0x1AA8, 0x1AE8, + 0x1B28, 0x1B68, 0x1BA8, 0x1BE8, + 0x1C28, 0x1C68, 0x1CA8, 0x1CE8, + 0x1D28, 0x1D68, 0x1DC8, 0x1E08, /* 80 */ + 0x1E48, 0x1E88, 0x1EC8, 0x1F08, + 0x1F48, 0x1F88, 0x1FE8, 0x2028, + 0x2068, 0x20A8, 0x2108, 0x2148, + 0x2188, 0x21C8, 0x2228, 0x2268, /* 96 */ + 0x22C8, 0x2308, 0x2348, 0x23A8, + 0x23E8, 0x2448, 0x24A8, 0x24E8, + 0x2548, 0x25A8, 0x2608, 0x2668, + 0x26C8, 0x2728, 0x2787, 0x27E7, /* 112 */ + 0x2847, 0x28C7, 0x2947, 0x29A7, + 0x2A27, 0x2AC7, 0x2B47, 0x2BE7, + 0x2CA7, 0x2D67, 0x2E47, 0x2F67, + 0x3247, 0x3526, 0x3646, 0x3726, /* 128 */ + 0x3806, 0x38A6, 0x3946, 0x39E6, + 0x3A66, 0x3AE6, 0x3B66, 0x3BC6, + 0x3C45, 0x3CA5, 0x3D05, 0x3D85, + 0x3DE5, 0x3E45, 0x3EA5, 0x3EE5, /* 144 */ + 0x3F45, 0x3FA5, 0x4005, 0x4045, + 0x40A5, 0x40E5, 0x4145, 0x4185, + 0x41E5, 0x4225, 0x4265, 0x42C5, + 0x4305, 0x4345, 0x43A5, 0x43E5, /* 160 */ + 0x4424, 0x4464, 0x44C4, 0x4504, + 0x4544, 0x4584, 0x45C4, 0x4604, + 0x4644, 0x46A4, 0x46E4, 0x4724, + 0x4764, 0x47A4, 0x47E4, 0x4824, /* 176 */ + 0x4864, 0x48A4, 0x48E4, 0x4924, + 0x4964, 0x49A4, 0x49E4, 0x4A24, + 0x4A64, 0x4AA4, 0x4AE4, 0x4B23, + 0x4B63, 0x4BA3, 0x4BE3, 0x4C23, /* 192 */ + 0x4C63, 0x4CA3, 0x4CE3, 0x4D23, + 0x4D63, 0x4DA3, 0x4DE3, 0x4E23, + 0x4E63, 0x4EA3, 0x4EE3, 0x4F23, + 0x4F63, 0x4FC3, 0x5003, 0x5043, /* 208 */ + 0x5083, 0x50C3, 0x5103, 0x5143, + 0x5183, 0x51E2, 0x5222, 0x5262, + 0x52A2, 0x52E2, 0x5342, 0x5382, + 0x53C2, 0x5402, 0x5462, 0x54A2, /* 224 */ + 0x5502, 0x5542, 0x55A2, 0x55E2, + 0x5642, 0x5682, 0x56E2, 0x5722, + 0x5782, 0x57E1, 0x5841, 0x58A1, + 0x5901, 0x5961, 0x59C1, 0x5A21, /* 240 */ + 0x5AA1, 0x5B01, 0x5B81, 0x5BE1, + 0x5C61, 0x5D01, 0x5D80, 0x5E20, + 0x5EE0, 0x5FA0, 0x6080, 0x61C0, +}; + +const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE] = { + 0x0001, 0x0001, 0x0001, 0xFFFE, + 0xFFFE, 0x3FFF, 0x1000, 0x0393, +}; + +const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE] = { + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, + 0x4C4C, 0x4C4C, 0x4C4C, 0x2D36, +}; + +const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE] = { + 0x013C, 0x01F5, 0x031A, 0x0631, + 0x0001, 0x0001, 0x0001, 0x0001, +}; + +const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE] = { + 0x5484, 0x3C40, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, +}; + +const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE] = { + 0x6C77, 0x5162, 0x3B40, 0x3335, /* 0 */ + 0x2F2D, 0x2A2A, 0x2527, 0x1F21, + 0x1A1D, 0x1719, 0x1616, 0x1414, + 0x1414, 0x1400, 0x1414, 0x1614, + 0x1716, 0x1A19, 0x1F1D, 0x2521, /* 16 */ + 0x2A27, 0x2F2A, 0x332D, 0x3B35, + 0x5140, 0x6C62, 0x0077, +}; + +const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE] = { + 0xD8DD, 0xCBD4, 0xBCC0, 0XB6B7, /* 0 */ + 0xB2B0, 0xADAD, 0xA7A9, 0x9FA1, + 0x969B, 0x9195, 0x8F8F, 0x8A8A, + 0x8A8A, 0x8A00, 0x8A8A, 0x8F8A, + 0x918F, 0x9695, 0x9F9B, 0xA7A1, /* 16 */ + 0xADA9, 0xB2AD, 0xB6B0, 0xBCB7, + 0xCBC0, 0xD8D4, 0x00DD, +}; + +const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE] = { + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 0 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA400, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, /* 16 */ + 0xA4A4, 0xA4A4, 0xA4A4, 0xA4A4, + 0xA4A4, 0xA4A4, 0x00A4, +}; + +const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE] = { + 0x007A, 0x0075, 0x0071, 0x006C, /* 0 */ + 0x0067, 0x0063, 0x005E, 0x0059, + 0x0054, 0x0050, 0x004B, 0x0046, + 0x0042, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 16 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x0000, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, + 0x003D, 0x003D, 0x003D, 0x003D, /* 32 */ + 0x003D, 0x003D, 0x003D, 0x003D, + 0x0042, 0x0046, 0x004B, 0x0050, + 0x0054, 0x0059, 0x005E, 0x0063, + 0x0067, 0x006C, 0x0071, 0x0075, /* 48 */ + 0x007A, +}; + +const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE] = { + 0x00DE, 0x00DC, 0x00DA, 0x00D8, /* 0 */ + 0x00D6, 0x00D4, 0x00D2, 0x00CF, + 0x00CD, 0x00CA, 0x00C7, 0x00C4, + 0x00C1, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 16 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x0000, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00BE, 0x00BE, 0x00BE, 0x00BE, /* 32 */ + 0x00BE, 0x00BE, 0x00BE, 0x00BE, + 0x00C1, 0x00C4, 0x00C7, 0x00CA, + 0x00CD, 0x00CF, 0x00D2, 0x00D4, + 0x00D6, 0x00D8, 0x00DA, 0x00DC, /* 48 */ + 0x00DE, +}; + +/**** Helper functions to access the device Internal Lookup Tables ****/ + +void bcm43xx_ilt_write16(struct bcm43xx_private *bcm, u16 offset, u16 val) +{ + if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val); + } else { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val); + } +} + +u16 bcm43xx_ilt_read16(struct bcm43xx_private *bcm, u16 offset) +{ + if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); + return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1); + } else { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); + return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1); + } +} + +void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val) +{ + if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA2, (u16)(val >> 16)); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, (u16)(val & 0x0000FFFF)); + } else { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA2, (u16)(val >> 16)); + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, (u16)(val & 0x0000FFFF)); + } +} + +u32 bcm43xx_ilt_read32(struct bcm43xx_private *bcm, u16 offset) +{ + u32 ret; + + if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); + ret = bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA2); + ret <<= 16; + ret |= bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1); + } else { + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); + ret = bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA2); + ret <<= 16; + ret |= bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1); + } + + return ret; +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h new file mode 100644 index 00000000000..d92527fd83e --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h @@ -0,0 +1,34 @@ +#ifndef BCM43xx_ILT_H_ +#define BCM43xx_ILT_H_ + +#define BCM43xx_ILT_ROTOR_SIZE 53 +extern const u32 bcm43xx_ilt_rotor[BCM43xx_ILT_ROTOR_SIZE]; +#define BCM43xx_ILT_RETARD_SIZE 53 +extern const u32 bcm43xx_ilt_retard[BCM43xx_ILT_RETARD_SIZE]; +#define BCM43xx_ILT_FINEFREQA_SIZE 256 +extern const u16 bcm43xx_ilt_finefreqa[BCM43xx_ILT_FINEFREQA_SIZE]; +#define BCM43xx_ILT_FINEFREQG_SIZE 256 +extern const u16 bcm43xx_ilt_finefreqg[BCM43xx_ILT_FINEFREQG_SIZE]; +#define BCM43xx_ILT_NOISEA2_SIZE 8 +extern const u16 bcm43xx_ilt_noisea2[BCM43xx_ILT_NOISEA2_SIZE]; +#define BCM43xx_ILT_NOISEA3_SIZE 8 +extern const u16 bcm43xx_ilt_noisea3[BCM43xx_ILT_NOISEA3_SIZE]; +#define BCM43xx_ILT_NOISEG1_SIZE 8 +extern const u16 bcm43xx_ilt_noiseg1[BCM43xx_ILT_NOISEG1_SIZE]; +#define BCM43xx_ILT_NOISEG2_SIZE 8 +extern const u16 bcm43xx_ilt_noiseg2[BCM43xx_ILT_NOISEG2_SIZE]; +#define BCM43xx_ILT_NOISESCALEG_SIZE 27 +extern const u16 bcm43xx_ilt_noisescaleg1[BCM43xx_ILT_NOISESCALEG_SIZE]; +extern const u16 bcm43xx_ilt_noisescaleg2[BCM43xx_ILT_NOISESCALEG_SIZE]; +extern const u16 bcm43xx_ilt_noisescaleg3[BCM43xx_ILT_NOISESCALEG_SIZE]; +#define BCM43xx_ILT_SIGMASQR_SIZE 53 +extern const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE]; +extern const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE]; + + +void bcm43xx_ilt_write16(struct bcm43xx_private *bcm, u16 offset, u16 val); +u16 bcm43xx_ilt_read16(struct bcm43xx_private *bcm, u16 offset); +void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val); +u32 bcm43xx_ilt_read32(struct bcm43xx_private *bcm, u16 offset); + +#endif /* BCM43xx_ILT_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c new file mode 100644 index 00000000000..455a0c743f7 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -0,0 +1,261 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx_leds.h" +#include "bcm43xx.h" + +#include + + +static void bcm43xx_led_changestate(struct bcm43xx_led *led) +{ + struct bcm43xx_private *bcm = led->bcm; + const int index = bcm43xx_led_index(led); + u16 ledctl; + + assert(index >= 0 && index < BCM43xx_NR_LEDS); + assert(led->blink_interval); + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); + __change_bit(index, (unsigned long *)(&ledctl)); + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); +} + +static void bcm43xx_led_blink(unsigned long d) +{ + struct bcm43xx_led *led = (struct bcm43xx_led *)d; + struct bcm43xx_private *bcm = led->bcm; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + if (led->blink_interval) { + bcm43xx_led_changestate(led); + mod_timer(&led->blink_timer, jiffies + led->blink_interval); + } + spin_unlock_irqrestore(&bcm->lock, flags); +} + +static void bcm43xx_led_blink_start(struct bcm43xx_led *led, + unsigned long interval) +{ + led->blink_interval = interval; + bcm43xx_led_changestate(led); + led->blink_timer.expires = jiffies + interval; + add_timer(&led->blink_timer); +} + +static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync) +{ + struct bcm43xx_private *bcm = led->bcm; + const int index = bcm43xx_led_index(led); + u16 ledctl; + + if (!led->blink_interval) + return; + if (unlikely(sync)) + del_timer_sync(&led->blink_timer); + else + del_timer(&led->blink_timer); + led->blink_interval = 0; + + /* Make sure the LED is turned off. */ + assert(index >= 0 && index < BCM43xx_NR_LEDS); + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); + if (led->activelow) + ledctl |= (1 << index); + else + ledctl &= ~(1 << index); + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); +} + +int bcm43xx_leds_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_led *led; + u8 sprom[4]; + int i; + + sprom[0] = bcm->sprom.wl0gpio0; + sprom[1] = bcm->sprom.wl0gpio1; + sprom[2] = bcm->sprom.wl0gpio2; + sprom[3] = bcm->sprom.wl0gpio3; + + for (i = 0; i < BCM43xx_NR_LEDS; i++) { + led = &(bcm->leds[i]); + led->bcm = bcm; + init_timer(&led->blink_timer); + led->blink_timer.data = (unsigned long)led; + led->blink_timer.function = bcm43xx_led_blink; + + if (sprom[i] == 0xFF) { + /* SPROM information not set. */ + switch (i) { + case 0: + if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ) + led->behaviour = BCM43xx_LED_RADIO_ALL; + else + led->behaviour = BCM43xx_LED_ACTIVITY; + break; + case 1: + led->behaviour = BCM43xx_LED_RADIO_B; + break; + case 2: + led->behaviour = BCM43xx_LED_RADIO_A; + break; + case 3: + led->behaviour = BCM43xx_LED_OFF; + break; + default: + assert(0); + } + } else { + led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR; + led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW); + } + } + + return 0; +} + +void bcm43xx_leds_exit(struct bcm43xx_private *bcm) +{ + struct bcm43xx_led *led; + int i; + + for (i = 0; i < BCM43xx_NR_LEDS; i++) { + led = &(bcm->leds[i]); + bcm43xx_led_blink_stop(led, 1); + } + bcm43xx_leds_turn_off(bcm); +} + +void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) +{ + struct bcm43xx_led *led; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES; + int i, turn_on = 0; + unsigned long interval = 0; + u16 ledctl; + + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); + for (i = 0; i < BCM43xx_NR_LEDS; i++) { + led = &(bcm->leds[i]); + if (led->behaviour == BCM43xx_LED_INACTIVE) + continue; + + switch (led->behaviour) { + case BCM43xx_LED_OFF: + turn_on = 0; + break; + case BCM43xx_LED_ON: + turn_on = 1; + break; + case BCM43xx_LED_ACTIVITY: + turn_on = activity; + break; + case BCM43xx_LED_RADIO_ALL: + turn_on = radio->enabled; + break; + case BCM43xx_LED_RADIO_A: + turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A); + break; + case BCM43xx_LED_RADIO_B: + turn_on = (radio->enabled && + (phy->type == BCM43xx_PHYTYPE_B || + phy->type == BCM43xx_PHYTYPE_G)); + break; + case BCM43xx_LED_MODE_BG: + turn_on = 0; + if (phy->type == BCM43xx_PHYTYPE_G && + 1/*FIXME: using G rates.*/) + turn_on = 1; + break; + case BCM43xx_LED_TRANSFER: + if (transferring) + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM); + else + bcm43xx_led_blink_stop(led, 0); + continue; + case BCM43xx_LED_APTRANSFER: + if (bcm->ieee->iw_mode == IW_MODE_MASTER) { + if (transferring) { + interval = BCM43xx_LEDBLINK_FAST; + turn_on = 1; + } + } else { + turn_on = 1; + if (0/*TODO: not assoc*/) + interval = BCM43xx_LEDBLINK_SLOW; + else if (transferring) + interval = BCM43xx_LEDBLINK_FAST; + else + turn_on = 0; + } + if (turn_on) + bcm43xx_led_blink_start(led, interval); + else + bcm43xx_led_blink_stop(led, 0); + continue; + case BCM43xx_LED_WEIRD: + //TODO + turn_on = 0; + break; + case BCM43xx_LED_ASSOC: + if (1/*TODO: associated*/) + turn_on = 1; + break; + default: + assert(0); + }; + + if (led->activelow) + turn_on = !turn_on; + if (turn_on) + ledctl |= (1 << i); + else + ledctl &= ~(1 << i); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); +} + +void bcm43xx_leds_turn_off(struct bcm43xx_private *bcm) +{ + struct bcm43xx_led *led; + u16 ledctl = 0; + int i; + + for (i = 0; i < BCM43xx_NR_LEDS; i++) { + led = &(bcm->leds[i]); + if (led->behaviour == BCM43xx_LED_INACTIVE) + continue; + if (led->activelow) + ledctl |= (1 << i); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); +} + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h new file mode 100644 index 00000000000..489a2b1e906 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h @@ -0,0 +1,47 @@ +#ifndef BCM43xx_LEDS_H_ +#define BCM43xx_LEDS_H_ + +#include +#include + + +struct bcm43xx_led { + u8 behaviour:7; + u8 activelow:1; + + struct bcm43xx_private *bcm; + struct timer_list blink_timer; + unsigned long blink_interval; +}; +#define bcm43xx_led_index(led) ((int)((led) - (led)->bcm->leds)) + +/* Delay between state changes when blinking in jiffies */ +#define BCM43xx_LEDBLINK_SLOW (HZ / 2) +#define BCM43xx_LEDBLINK_MEDIUM (HZ / 4) +#define BCM43xx_LEDBLINK_FAST (HZ / 8) + +#define BCM43xx_LED_XFER_THRES (HZ / 100) + +#define BCM43xx_LED_BEHAVIOUR 0x7F +#define BCM43xx_LED_ACTIVELOW 0x80 +enum { /* LED behaviour values */ + BCM43xx_LED_OFF, + BCM43xx_LED_ON, + BCM43xx_LED_ACTIVITY, + BCM43xx_LED_RADIO_ALL, + BCM43xx_LED_RADIO_A, + BCM43xx_LED_RADIO_B, + BCM43xx_LED_MODE_BG, + BCM43xx_LED_TRANSFER, + BCM43xx_LED_APTRANSFER, + BCM43xx_LED_WEIRD,//FIXME + BCM43xx_LED_ASSOC, + BCM43xx_LED_INACTIVE, +}; + +int bcm43xx_leds_init(struct bcm43xx_private *bcm); +void bcm43xx_leds_exit(struct bcm43xx_private *bcm); +void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity); +void bcm43xx_leds_turn_off(struct bcm43xx_private *bcm); + +#endif /* BCM43xx_LEDS_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c new file mode 100644 index 00000000000..be60a6509f2 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -0,0 +1,4597 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "bcm43xx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_debugfs.h" +#include "bcm43xx_radio.h" +#include "bcm43xx_phy.h" +#include "bcm43xx_dma.h" +#include "bcm43xx_pio.h" +#include "bcm43xx_power.h" +#include "bcm43xx_wx.h" + + +MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); +MODULE_AUTHOR("Martin Langer"); +MODULE_AUTHOR("Stefano Brivio"); +MODULE_AUTHOR("Michael Buesch"); +MODULE_LICENSE("GPL"); + +#ifdef CONFIG_BCM947XX +extern char *nvram_get(char *name); +#endif + +/* Module parameters */ +static int modparam_pio; +module_param_named(pio, modparam_pio, int, 0444); +MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); + +static int modparam_bad_frames_preempt; +module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); +MODULE_PARM_DESC(bad_frames_preempt, "enable(1) / disable(0) Bad Frames Preemption"); + +static int modparam_short_retry = BCM43xx_DEFAULT_SHORT_RETRY_LIMIT; +module_param_named(short_retry, modparam_short_retry, int, 0444); +MODULE_PARM_DESC(short_retry, "Short-Retry-Limit (0 - 15)"); + +static int modparam_long_retry = BCM43xx_DEFAULT_LONG_RETRY_LIMIT; +module_param_named(long_retry, modparam_long_retry, int, 0444); +MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); + +static int modparam_locale = -1; +module_param_named(locale, modparam_locale, int, 0444); +MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)"); + +static int modparam_outdoor; +module_param_named(outdoor, modparam_outdoor, int, 0444); +MODULE_PARM_DESC(outdoor, "Set to 1, if you are using the device outdoor, 0 otherwise."); + +static int modparam_noleds; +module_param_named(noleds, modparam_noleds, int, 0444); +MODULE_PARM_DESC(noleds, "Turn off all LED activity"); + +#ifdef CONFIG_BCM43XX_DEBUG +static char modparam_fwpostfix[64]; +module_param_string(fwpostfix, modparam_fwpostfix, 64, 0444); +MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging."); +#else +# define modparam_fwpostfix "" +#endif /* CONFIG_BCM43XX_DEBUG*/ + + +/* If you want to debug with just a single device, enable this, + * where the string is the pci device ID (as given by the kernel's + * pci_name function) of the device to be used. + */ +//#define DEBUG_SINGLE_DEVICE_ONLY "0001:11:00.0" + +/* If you want to enable printing of each MMIO access, enable this. */ +//#define DEBUG_ENABLE_MMIO_PRINT + +/* If you want to enable printing of MMIO access within + * ucode/pcm upload, initvals write, enable this. + */ +//#define DEBUG_ENABLE_UCODE_MMIO_PRINT + +/* If you want to enable printing of PCI Config Space access, enable this */ +//#define DEBUG_ENABLE_PCILOG + + +static struct pci_device_id bcm43xx_pci_tbl[] = { + + /* Detailed list maintained at: + * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices + */ + +#ifdef CONFIG_BCM947XX + /* SB bus on BCM947xx */ + { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#endif + + /* Broadcom 4303 802.11b */ + { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* Broadcom 4307 802.11b */ + { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* Broadcom 4318 802.11b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* Broadcom 4306 802.11b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* Broadcom 4306 802.11a */ +// { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* Broadcom 4309 802.11a/b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* Broadcom 43XG 802.11b/g */ + { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + + /* required last entry */ + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl); + +static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val) +{ + u32 status; + + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + if (!(status & BCM43xx_SBF_XFER_REG_BYTESWAP)) + val = swab32(val); + + bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset); + bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val); +} + +static inline +void bcm43xx_shm_control_word(struct bcm43xx_private *bcm, + u16 routing, u16 offset) +{ + u32 control; + + /* "offset" is the WORD offset. */ + + control = routing; + control <<= 16; + control |= offset; + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_CONTROL, control); +} + +u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm, + u16 routing, u16 offset) +{ + u32 ret; + + if (routing == BCM43xx_SHM_SHARED) { + if (offset & 0x0003) { + /* Unaligned access */ + bcm43xx_shm_control_word(bcm, routing, offset >> 2); + ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED); + ret <<= 16; + bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); + ret |= bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA); + + return ret; + } + offset >>= 2; + } + bcm43xx_shm_control_word(bcm, routing, offset); + ret = bcm43xx_read32(bcm, BCM43xx_MMIO_SHM_DATA); + + return ret; +} + +u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm, + u16 routing, u16 offset) +{ + u16 ret; + + if (routing == BCM43xx_SHM_SHARED) { + if (offset & 0x0003) { + /* Unaligned access */ + bcm43xx_shm_control_word(bcm, routing, offset >> 2); + ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED); + + return ret; + } + offset >>= 2; + } + bcm43xx_shm_control_word(bcm, routing, offset); + ret = bcm43xx_read16(bcm, BCM43xx_MMIO_SHM_DATA); + + return ret; +} + +void bcm43xx_shm_write32(struct bcm43xx_private *bcm, + u16 routing, u16 offset, + u32 value) +{ + if (routing == BCM43xx_SHM_SHARED) { + if (offset & 0x0003) { + /* Unaligned access */ + bcm43xx_shm_control_word(bcm, routing, offset >> 2); + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, + (value >> 16) & 0xffff); + bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, + value & 0xffff); + return; + } + offset >>= 2; + } + bcm43xx_shm_control_word(bcm, routing, offset); + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value); +} + +void bcm43xx_shm_write16(struct bcm43xx_private *bcm, + u16 routing, u16 offset, + u16 value) +{ + if (routing == BCM43xx_SHM_SHARED) { + if (offset & 0x0003) { + /* Unaligned access */ + bcm43xx_shm_control_word(bcm, routing, offset >> 2); + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, + value); + return; + } + offset >>= 2; + } + bcm43xx_shm_control_word(bcm, routing, offset); + bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value); +} + +void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf) +{ + /* We need to be careful. As we read the TSF from multiple + * registers, we should take care of register overflows. + * In theory, the whole tsf read process should be atomic. + * We try to be atomic here, by restaring the read process, + * if any of the high registers changed (overflew). + */ + if (bcm->current_core->rev >= 3) { + u32 low, high, high2; + + do { + high = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH); + low = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW); + high2 = bcm43xx_read32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH); + } while (unlikely(high != high2)); + + *tsf = high; + *tsf <<= 32; + *tsf |= low; + } else { + u64 tmp; + u16 v0, v1, v2, v3; + u16 test1, test2, test3; + + do { + v3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3); + v2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2); + v1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1); + v0 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_0); + + test3 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_3); + test2 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_2); + test1 = bcm43xx_read16(bcm, BCM43xx_MMIO_TSF_1); + } while (v3 != test3 || v2 != test2 || v1 != test1); + + *tsf = v3; + *tsf <<= 48; + tmp = v2; + tmp <<= 32; + *tsf |= tmp; + tmp = v1; + tmp <<= 16; + *tsf |= tmp; + *tsf |= v0; + } +} + +void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) +{ + u32 status; + + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + status |= BCM43xx_SBF_TIME_UPDATE; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + + /* Be careful with the in-progress timer. + * First zero out the low register, so we have a full + * register-overflow duration to complete the operation. + */ + if (bcm->current_core->rev >= 3) { + u32 lo = (tsf & 0x00000000FFFFFFFFULL); + u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32; + + barrier(); + bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0); + bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi); + bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo); + } else { + u16 v0 = (tsf & 0x000000000000FFFFULL); + u16 v1 = (tsf & 0x00000000FFFF0000ULL) >> 16; + u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32; + u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48; + + barrier(); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1); + bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0); + } + + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + status &= ~BCM43xx_SBF_TIME_UPDATE; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); +} + +static inline +u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp, + const int ofdm_modulation) +{ + u8 rate; + + if (ofdm_modulation) { + switch (plcp->raw[0] & 0xF) { + case 0xB: + rate = IEEE80211_OFDM_RATE_6MB; + break; + case 0xF: + rate = IEEE80211_OFDM_RATE_9MB; + break; + case 0xA: + rate = IEEE80211_OFDM_RATE_12MB; + break; + case 0xE: + rate = IEEE80211_OFDM_RATE_18MB; + break; + case 0x9: + rate = IEEE80211_OFDM_RATE_24MB; + break; + case 0xD: + rate = IEEE80211_OFDM_RATE_36MB; + break; + case 0x8: + rate = IEEE80211_OFDM_RATE_48MB; + break; + case 0xC: + rate = IEEE80211_OFDM_RATE_54MB; + break; + default: + rate = 0; + assert(0); + } + } else { + switch (plcp->raw[0]) { + case 0x0A: + rate = IEEE80211_CCK_RATE_1MB; + break; + case 0x14: + rate = IEEE80211_CCK_RATE_2MB; + break; + case 0x37: + rate = IEEE80211_CCK_RATE_5MB; + break; + case 0x6E: + rate = IEEE80211_CCK_RATE_11MB; + break; + default: + rate = 0; + assert(0); + } + } + + return rate; +} + +static inline +u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) +{ + switch (bitrate) { + case IEEE80211_CCK_RATE_1MB: + return 0x0A; + case IEEE80211_CCK_RATE_2MB: + return 0x14; + case IEEE80211_CCK_RATE_5MB: + return 0x37; + case IEEE80211_CCK_RATE_11MB: + return 0x6E; + } + assert(0); + return 0; +} + +static inline +u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) +{ + switch (bitrate) { + case IEEE80211_OFDM_RATE_6MB: + return 0xB; + case IEEE80211_OFDM_RATE_9MB: + return 0xF; + case IEEE80211_OFDM_RATE_12MB: + return 0xA; + case IEEE80211_OFDM_RATE_18MB: + return 0xE; + case IEEE80211_OFDM_RATE_24MB: + return 0x9; + case IEEE80211_OFDM_RATE_36MB: + return 0xD; + case IEEE80211_OFDM_RATE_48MB: + return 0x8; + case IEEE80211_OFDM_RATE_54MB: + return 0xC; + } + assert(0); + return 0; +} + +static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp, + u16 octets, const u8 bitrate, + const int ofdm_modulation) +{ + __le32 *data = &(plcp->data); + __u8 *raw = plcp->raw; + + /* Account for hardware-appended FCS. */ + octets += IEEE80211_FCS_LEN; + + if (ofdm_modulation) { + *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate); + assert(!(octets & 0xF000)); + *data |= (octets << 5); + *data = cpu_to_le32(*data); + } else { + u32 plen; + + plen = octets * 16 / bitrate; + if ((octets * 16 % bitrate) > 0) { + plen++; + if ((bitrate == IEEE80211_CCK_RATE_11MB) + && ((octets * 8 % 11) < 4)) { + raw[1] = 0x84; + } else + raw[1] = 0x04; + } else + raw[1] = 0x04; + *data |= cpu_to_le32(plen << 16); + raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate); + } + +//bcm43xx_printk_bitdump(raw, 4, 0, "PLCP"); +} + +void fastcall +bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie) +{ + const struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + const struct ieee80211_hdr_1addr *wireless_header = (const struct ieee80211_hdr_1addr *)fragment_data; + const struct ieee80211_security *secinfo = &bcm->ieee->sec; + u8 bitrate; + int ofdm_modulation; + u8 fallback_bitrate; + int fallback_ofdm_modulation; + u16 tmp; + u16 encrypt_frame; + + /* Now construct the TX header. */ + memset(txhdr, 0, sizeof(*txhdr)); + + //TODO: Some RTS/CTS stuff has to be done. + //TODO: Encryption stuff. + //TODO: others? + + bitrate = bcm->softmac->txrates.default_rate; + ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); + fallback_bitrate = bcm->softmac->txrates.default_fallback; + fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); + + /* Set Frame Control from 80211 header. */ + txhdr->frame_control = wireless_header->frame_ctl; + /* Copy address1 from 80211 header. */ + memcpy(txhdr->mac1, wireless_header->addr1, 6); + /* Set the fallback duration ID. */ + //FIXME: We use the original durid for now. + txhdr->fallback_dur_id = wireless_header->duration_id; + + /* Set the cookie (used as driver internal ID for the frame) */ + txhdr->cookie = cpu_to_le16(cookie); + + encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED; + if (encrypt_frame && !bcm->ieee->host_encrypt) { + const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header; + if (fragment_len <= sizeof(struct ieee80211_hdr_3addr)+4) { + dprintkl(KERN_ERR PFX "invalid packet with PROTECTED" + "flag set discarded"); + return; + } + memcpy(txhdr->wep_iv, hdr->payload, 4); + /* Hardware appends ICV. */ + fragment_len += 4; + } + + /* Generate the PLCP header and the fallback PLCP header. */ + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp), + fragment_len, + bitrate, ofdm_modulation); + bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, fragment_len, + fallback_bitrate, fallback_ofdm_modulation); + + /* Set the CONTROL field */ + tmp = 0; + if (ofdm_modulation) + tmp |= BCM43xx_TXHDRCTL_OFDM; + if (bcm->short_preamble) //FIXME: could be the other way around, please test + tmp |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE; + tmp |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT) + & BCM43xx_TXHDRCTL_ANTENNADIV_MASK; + txhdr->control = cpu_to_le16(tmp); + + /* Set the FLAGS field */ + tmp = 0; + if (!is_multicast_ether_addr(wireless_header->addr1) && + !is_broadcast_ether_addr(wireless_header->addr1)) + tmp |= BCM43xx_TXHDRFLAG_EXPECTACK; + if (1 /* FIXME: PS poll?? */) + tmp |= 0x10; // FIXME: unknown meaning. + if (fallback_ofdm_modulation) + tmp |= BCM43xx_TXHDRFLAG_FALLBACKOFDM; + if (is_first_fragment) + tmp |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT; + txhdr->flags = cpu_to_le16(tmp); + + /* Set WSEC/RATE field */ + if (encrypt_frame && !bcm->ieee->host_encrypt) { + tmp = (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT) + & BCM43xx_TXHDR_WSEC_ALGO_MASK; + tmp |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT) + & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK; + txhdr->wsec_rate = cpu_to_le16(tmp); + } + +//bcm43xx_printk_bitdump((const unsigned char *)txhdr, sizeof(*txhdr), 1, "TX header"); +} + +static +void bcm43xx_macfilter_set(struct bcm43xx_private *bcm, + u16 offset, + const u8 *mac) +{ + u16 data; + + offset |= 0x0020; + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_CONTROL, offset); + + data = mac[0]; + data |= mac[1] << 8; + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); + data = mac[2]; + data |= mac[3] << 8; + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); + data = mac[4]; + data |= mac[5] << 8; + bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); +} + +static inline +void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm, + u16 offset) +{ + const u8 zero_addr[ETH_ALEN] = { 0 }; + + bcm43xx_macfilter_set(bcm, offset, zero_addr); +} + +static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm) +{ + const u8 *mac = (const u8 *)(bcm->net_dev->dev_addr); + const u8 *bssid = (const u8 *)(bcm->ieee->bssid); + u8 mac_bssid[ETH_ALEN * 2]; + int i; + + memcpy(mac_bssid, mac, ETH_ALEN); + memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN); + + /* Write our MAC address and BSSID to template ram */ + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) + bcm43xx_ram_write(bcm, 0x20 + i, *((u32 *)(mac_bssid + i))); + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) + bcm43xx_ram_write(bcm, 0x78 + i, *((u32 *)(mac_bssid + i))); + for (i = 0; i < ARRAY_SIZE(mac_bssid); i += sizeof(u32)) + bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i))); +} + +static inline +void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) +{ + /* slot_time is in usec. */ + if (bcm->current_core->phy->type != BCM43xx_PHYTYPE_G) + return; + bcm43xx_write16(bcm, 0x684, 510 + slot_time); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time); +} + +static inline +void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm) +{ + bcm43xx_set_slot_time(bcm, 9); +} + +static inline +void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm) +{ + bcm43xx_set_slot_time(bcm, 20); +} + +//FIXME: rename this func? +static void bcm43xx_disassociate(struct bcm43xx_private *bcm) +{ + bcm43xx_mac_suspend(bcm); + bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); + + bcm43xx_ram_write(bcm, 0x0026, 0x0000); + bcm43xx_ram_write(bcm, 0x0028, 0x0000); + bcm43xx_ram_write(bcm, 0x007E, 0x0000); + bcm43xx_ram_write(bcm, 0x0080, 0x0000); + bcm43xx_ram_write(bcm, 0x047E, 0x0000); + bcm43xx_ram_write(bcm, 0x0480, 0x0000); + + if (bcm->current_core->rev < 3) { + bcm43xx_write16(bcm, 0x0610, 0x8000); + bcm43xx_write16(bcm, 0x060E, 0x0000); + } else + bcm43xx_write32(bcm, 0x0188, 0x80000000); + + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G && + ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate)) + bcm43xx_short_slot_timing_enable(bcm); + + bcm43xx_mac_enable(bcm); +} + +//FIXME: rename this func? +static void bcm43xx_associate(struct bcm43xx_private *bcm, + const u8 *mac) +{ + memcpy(bcm->ieee->bssid, mac, ETH_ALEN); + + bcm43xx_mac_suspend(bcm); + bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_ASSOC, mac); + bcm43xx_write_mac_bssid_templates(bcm); + bcm43xx_mac_enable(bcm); +} + +/* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 bcm43xx_interrupt_enable(struct bcm43xx_private *bcm, u32 mask) +{ + u32 old_mask; + + old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask); + + return old_mask; +} + +/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. + * Returns the _previously_ enabled IRQ mask. + */ +static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask) +{ + u32 old_mask; + + old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask); + + return old_mask; +} + +/* Make sure we don't receive more data from the device. */ +static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate) +{ + u32 old; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) { + spin_unlock_irqrestore(&bcm->lock, flags); + return -EBUSY; + } + old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + tasklet_disable(&bcm->isr_tasklet); + spin_unlock_irqrestore(&bcm->lock, flags); + if (oldstate) + *oldstate = old; + + return 0; +} + +static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) +{ + u32 radio_id; + u16 manufact; + u16 version; + u8 revision; + s8 i; + + if (bcm->chip_id == 0x4317) { + if (bcm->chip_rev == 0x00) + radio_id = 0x3205017F; + else if (bcm->chip_rev == 0x01) + radio_id = 0x4205017F; + else + radio_id = 0x5205017F; + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID); + radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH); + radio_id <<= 16; + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID); + radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW); + } + + manufact = (radio_id & 0x00000FFF); + version = (radio_id & 0x0FFFF000) >> 12; + revision = (radio_id & 0xF0000000) >> 28; + + dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n", + radio_id, manufact, version, revision); + + switch (bcm->current_core->phy->type) { + case BCM43xx_PHYTYPE_A: + if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f)) + goto err_unsupported_radio; + break; + case BCM43xx_PHYTYPE_B: + if ((version & 0xFFF0) != 0x2050) + goto err_unsupported_radio; + break; + case BCM43xx_PHYTYPE_G: + if (version != 0x2050) + goto err_unsupported_radio; + break; + } + + bcm->current_core->radio->manufact = manufact; + bcm->current_core->radio->version = version; + bcm->current_core->radio->revision = revision; + + /* Set default attenuation values. */ + bcm->current_core->radio->txpower[0] = 2; + bcm->current_core->radio->txpower[1] = 2; + if (revision == 1) + bcm->current_core->radio->txpower[2] = 3; + else + bcm->current_core->radio->txpower[2] = 0; + + /* Initialize the in-memory nrssi Lookup Table. */ + for (i = 0; i < 64; i++) + bcm->current_core->radio->nrssi_lt[i] = i; + + return 0; + +err_unsupported_radio: + printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n"); + return -ENODEV; +} + +static const char * bcm43xx_locale_iso(u8 locale) +{ + /* ISO 3166-1 country codes. + * Note that there aren't ISO 3166-1 codes for + * all or locales. (Not all locales are countries) + */ + switch (locale) { + case BCM43xx_LOCALE_WORLD: + case BCM43xx_LOCALE_ALL: + return "XX"; + case BCM43xx_LOCALE_THAILAND: + return "TH"; + case BCM43xx_LOCALE_ISRAEL: + return "IL"; + case BCM43xx_LOCALE_JORDAN: + return "JO"; + case BCM43xx_LOCALE_CHINA: + return "CN"; + case BCM43xx_LOCALE_JAPAN: + case BCM43xx_LOCALE_JAPAN_HIGH: + return "JP"; + case BCM43xx_LOCALE_USA_CANADA_ANZ: + case BCM43xx_LOCALE_USA_LOW: + return "US"; + case BCM43xx_LOCALE_EUROPE: + return "EU"; + case BCM43xx_LOCALE_NONE: + return " "; + } + assert(0); + return " "; +} + +static const char * bcm43xx_locale_string(u8 locale) +{ + switch (locale) { + case BCM43xx_LOCALE_WORLD: + return "World"; + case BCM43xx_LOCALE_THAILAND: + return "Thailand"; + case BCM43xx_LOCALE_ISRAEL: + return "Israel"; + case BCM43xx_LOCALE_JORDAN: + return "Jordan"; + case BCM43xx_LOCALE_CHINA: + return "China"; + case BCM43xx_LOCALE_JAPAN: + return "Japan"; + case BCM43xx_LOCALE_USA_CANADA_ANZ: + return "USA/Canada/ANZ"; + case BCM43xx_LOCALE_EUROPE: + return "Europe"; + case BCM43xx_LOCALE_USA_LOW: + return "USAlow"; + case BCM43xx_LOCALE_JAPAN_HIGH: + return "JapanHigh"; + case BCM43xx_LOCALE_ALL: + return "All"; + case BCM43xx_LOCALE_NONE: + return "None"; + } + assert(0); + return ""; +} + +static inline u8 bcm43xx_crc8(u8 crc, u8 data) +{ + static const u8 t[] = { + 0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B, + 0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21, + 0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF, + 0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5, + 0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14, + 0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E, + 0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80, + 0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA, + 0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95, + 0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF, + 0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01, + 0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B, + 0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA, + 0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0, + 0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E, + 0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34, + 0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0, + 0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A, + 0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54, + 0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E, + 0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF, + 0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5, + 0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B, + 0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61, + 0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E, + 0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74, + 0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA, + 0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0, + 0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41, + 0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B, + 0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5, + 0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F, + }; + return t[crc ^ data]; +} + +u8 bcm43xx_sprom_crc(const u16 *sprom) +{ + int word; + u8 crc = 0xFF; + + for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) { + crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF); + crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8); + } + crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF); + crc ^= 0xFF; + + return crc; +} + + +static int bcm43xx_read_sprom(struct bcm43xx_private *bcm) +{ + int i; + u16 value; + u16 *sprom; + u8 crc, expected_crc; +#ifdef CONFIG_BCM947XX + char *c; +#endif + + sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16), + GFP_KERNEL); + if (!sprom) { + printk(KERN_ERR PFX "read_sprom OOM\n"); + return -ENOMEM; + } +#ifdef CONFIG_BCM947XX + sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2")); + sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags")); + + if ((c = nvram_get("il0macaddr")) != NULL) + e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR])); + + if ((c = nvram_get("et1macaddr")) != NULL) + e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR])); + + sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0")); + sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1")); + sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2")); + + sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0")); + sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1")); + sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2")); + + sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev")); +#else + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) + sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2)); + + /* CRC-8 check. */ + crc = bcm43xx_sprom_crc(sprom); + expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; + if (crc != expected_crc) { + printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum " + "(0x%02X, expected: 0x%02X)\n", + crc, expected_crc); + } +#endif + + /* boardflags2 */ + value = sprom[BCM43xx_SPROM_BOARDFLAGS2]; + bcm->sprom.boardflags2 = value; + + /* il0macaddr */ + value = sprom[BCM43xx_SPROM_IL0MACADDR + 0]; + *(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_IL0MACADDR + 1]; + *(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_IL0MACADDR + 2]; + *(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value); + + /* et0macaddr */ + value = sprom[BCM43xx_SPROM_ET0MACADDR + 0]; + *(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_ET0MACADDR + 1]; + *(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_ET0MACADDR + 2]; + *(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value); + + /* et1macaddr */ + value = sprom[BCM43xx_SPROM_ET1MACADDR + 0]; + *(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_ET1MACADDR + 1]; + *(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value); + value = sprom[BCM43xx_SPROM_ET1MACADDR + 2]; + *(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value); + + /* ethernet phy settings */ + value = sprom[BCM43xx_SPROM_ETHPHY]; + bcm->sprom.et0phyaddr = (value & 0x001F); + bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5; + bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14; + bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15; + + /* boardrev, antennas, locale */ + value = sprom[BCM43xx_SPROM_BOARDREV]; + bcm->sprom.boardrev = (value & 0x00FF); + bcm->sprom.locale = (value & 0x0F00) >> 8; + bcm->sprom.antennas_aphy = (value & 0x3000) >> 12; + bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14; + if (modparam_locale != -1) { + if (modparam_locale >= 0 && modparam_locale <= 11) { + bcm->sprom.locale = modparam_locale; + printk(KERN_WARNING PFX "Operating with modified " + "LocaleCode %u (%s)\n", + bcm->sprom.locale, + bcm43xx_locale_string(bcm->sprom.locale)); + } else { + printk(KERN_WARNING PFX "Module parameter \"locale\" " + "invalid value. (0 - 11)\n"); + } + } + + /* pa0b* */ + value = sprom[BCM43xx_SPROM_PA0B0]; + bcm->sprom.pa0b0 = value; + value = sprom[BCM43xx_SPROM_PA0B1]; + bcm->sprom.pa0b1 = value; + value = sprom[BCM43xx_SPROM_PA0B2]; + bcm->sprom.pa0b2 = value; + + /* wl0gpio* */ + value = sprom[BCM43xx_SPROM_WL0GPIO0]; + if (value == 0x0000) + value = 0xFFFF; + bcm->sprom.wl0gpio0 = value & 0x00FF; + bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8; + value = sprom[BCM43xx_SPROM_WL0GPIO2]; + if (value == 0x0000) + value = 0xFFFF; + bcm->sprom.wl0gpio2 = value & 0x00FF; + bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8; + + /* maxpower */ + value = sprom[BCM43xx_SPROM_MAXPWR]; + bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8; + bcm->sprom.maxpower_bgphy = value & 0x00FF; + + /* pa1b* */ + value = sprom[BCM43xx_SPROM_PA1B0]; + bcm->sprom.pa1b0 = value; + value = sprom[BCM43xx_SPROM_PA1B1]; + bcm->sprom.pa1b1 = value; + value = sprom[BCM43xx_SPROM_PA1B2]; + bcm->sprom.pa1b2 = value; + + /* idle tssi target */ + value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT]; + bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF; + bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8; + + /* boardflags */ + value = sprom[BCM43xx_SPROM_BOARDFLAGS]; + if (value == 0xFFFF) + value = 0x0000; + bcm->sprom.boardflags = value; + + /* antenna gain */ + value = sprom[BCM43xx_SPROM_ANTENNA_GAIN]; + if (value == 0x0000 || value == 0xFFFF) + value = 0x0202; + /* convert values to Q5.2 */ + bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4; + bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4; + + kfree(sprom); + + return 0; +} + +static int bcm43xx_channel_is_allowed(struct bcm43xx_private *bcm, u8 channel, + u8 *max_power, u8 *flags) +{ + /* THIS FUNCTION DOES _NOT_ ENFORCE REGULATORY DOMAIN COMPLIANCE. + * It is only a helper function to make life easier to + * select legal channels and transmission powers. + */ + + u8 phytype = bcm->current_core->phy->type; + int allowed = 0; + + *max_power = 0; + *flags = 0; + + //FIXME: Set max_power and maybe flags + /*FIXME: Allowed channels are sometimes different for outdoor + * or indoor use. See modparam_outdoor. + */ + /* From b specs Max Power BPHY: + * USA: 1000mW + * Europe: 100mW + * Japan: 10mW/MHz + */ + + switch (bcm->sprom.locale) { + case BCM43xx_LOCALE_WORLD: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 1 && channel <= 13) + allowed = 1; + } else { + if (channel >= 1 && channel <= 13) + allowed = 1; + } + break; + case BCM43xx_LOCALE_THAILAND: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 1 && channel <= 14) + allowed = 1; + } else { + if (channel >= 1 && channel <= 14) + allowed = 1; + } + break; + case BCM43xx_LOCALE_ISRAEL: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 5 && channel <= 7) + allowed = 1; + } else { + if (channel >= 5 && channel <= 7) + allowed = 1; + } + break; + case BCM43xx_LOCALE_JORDAN: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 10 && channel <= 13) + allowed = 1; + } else { + if (channel >= 10 && channel <= 13) + allowed = 1; + } + break; + case BCM43xx_LOCALE_CHINA: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 1 && channel <= 13) + allowed = 1; + } else { + if (channel >= 1 && channel <= 13) + allowed = 1; + } + break; + case BCM43xx_LOCALE_JAPAN: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + //FIXME: This seems to be wrong. + if (channel >= 1 && channel <= 14) + allowed = 1; + } else { + //FIXME: This seems to be wrong. + if (channel >= 1 && channel <= 14) + allowed = 1; + } + break; + case BCM43xx_LOCALE_USA_CANADA_ANZ: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 1 && channel <= 13) + allowed = 1; + } else { + if (channel >= 1 && channel <= 11) + allowed = 1; + } + break; + case BCM43xx_LOCALE_EUROPE: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 1 && channel <= 13) + allowed = 1; + } else { + if (channel >= 1 && channel <= 13) + allowed = 1; + } + break; + case BCM43xx_LOCALE_USA_LOW: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + if (channel >= 1 && channel <= 13) + allowed = 1; + } else { + if (channel >= 1 && channel <= 11) + allowed = 1; + } + break; + case BCM43xx_LOCALE_JAPAN_HIGH: + if (phytype == BCM43xx_PHYTYPE_A) { + allowed = 1;//FIXME + } else if (phytype == BCM43xx_PHYTYPE_B) { + //FIXME? + if (channel >= 1 && channel <= 14) + allowed = 1; + } else { + if (channel >= 1 && channel <= 14) + allowed = 1; + } + break; + case BCM43xx_LOCALE_ALL: + allowed = 1; + break; + case BCM43xx_LOCALE_NONE: + break; + default: + assert(0); + } + + return allowed; +} + +static void bcm43xx_geo_init(struct bcm43xx_private *bcm) +{ + struct ieee80211_geo geo; + struct ieee80211_channel *chan; + int have_a = 0, have_bg = 0; + int i, num80211; + u8 channel, flags, max_power; + struct bcm43xx_phyinfo *phy; + const char *iso_country; + + memset(&geo, 0, sizeof(geo)); + num80211 = bcm43xx_num_80211_cores(bcm); + for (i = 0; i < num80211; i++) { + phy = bcm->phy + i; + switch (phy->type) { + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + have_bg = 1; + break; + case BCM43xx_PHYTYPE_A: + have_a = 1; + break; + default: + assert(0); + } + } + iso_country = bcm43xx_locale_iso(bcm->sprom.locale); + + if (have_a) { + for (i = 0, channel = 0; channel < 201; channel++) { + if (!bcm43xx_channel_is_allowed(bcm, channel, + &max_power, &flags)) + continue; + chan = &geo.a[i++]; + chan->freq = bcm43xx_channel_to_freq(bcm, channel); + chan->channel = channel; + chan->flags = flags; + chan->max_power = max_power; + } + geo.a_channels = i; + } + if (have_bg) { + for (i = 0, channel = 1; channel < 15; channel++) { + if (!bcm43xx_channel_is_allowed(bcm, channel, + &max_power, &flags)) + continue; + chan = &geo.bg[i++]; + chan->freq = bcm43xx_channel_to_freq(bcm, channel); + chan->channel = channel; + chan->flags = flags; + chan->max_power = max_power; + } + geo.bg_channels = i; + } + memcpy(geo.name, iso_country, 2); + if (0 /*TODO: Outdoor use only */) + geo.name[2] = 'O'; + else if (0 /*TODO: Indoor use only */) + geo.name[2] = 'I'; + else + geo.name[2] = ' '; + geo.name[3] = '\0'; + + ieee80211_set_geo(bcm->ieee, &geo); +} + +/* DummyTransmission function, as documented on + * http://bcm-specs.sipsolutions.net/DummyTransmission + */ +void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) +{ + unsigned int i, max_loop; + u16 value = 0; + u32 buffer[5] = { + 0x00000000, + 0x0000D400, + 0x00000000, + 0x00000001, + 0x00000000, + }; + + switch (bcm->current_core->phy->type) { + case BCM43xx_PHYTYPE_A: + max_loop = 0x1E; + buffer[0] = 0xCC010200; + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + max_loop = 0xFA; + buffer[0] = 0x6E840B00; + break; + default: + assert(0); + return; + } + + for (i = 0; i < 5; i++) + bcm43xx_ram_write(bcm, i * 4, buffer[i]); + + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ + + bcm43xx_write16(bcm, 0x0568, 0x0000); + bcm43xx_write16(bcm, 0x07C0, 0x0000); + bcm43xx_write16(bcm, 0x050C, ((bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0)); + bcm43xx_write16(bcm, 0x0508, 0x0000); + bcm43xx_write16(bcm, 0x050A, 0x0000); + bcm43xx_write16(bcm, 0x054C, 0x0000); + bcm43xx_write16(bcm, 0x056A, 0x0014); + bcm43xx_write16(bcm, 0x0568, 0x0826); + bcm43xx_write16(bcm, 0x0500, 0x0000); + bcm43xx_write16(bcm, 0x0502, 0x0030); + + for (i = 0x00; i < max_loop; i++) { + value = bcm43xx_read16(bcm, 0x050E); + if ((value & 0x0080) != 0) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = bcm43xx_read16(bcm, 0x050E); + if ((value & 0x0400) != 0) + break; + udelay(10); + } + for (i = 0x00; i < 0x0A; i++) { + value = bcm43xx_read16(bcm, 0x0690); + if ((value & 0x0100) == 0) + break; + udelay(10); + } +} + +static void key_write(struct bcm43xx_private *bcm, + u8 index, u8 algorithm, const u16 *key) +{ + unsigned int i, basic_wep = 0; + u32 offset; + u16 value; + + /* Write associated key information */ + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2), + ((index << 4) | (algorithm & 0x0F))); + + /* The first 4 WEP keys need extra love */ + if (((algorithm == BCM43xx_SEC_ALGO_WEP) || + (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4)) + basic_wep = 1; + + /* Write key payload, 8 little endian words */ + offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE); + for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) { + value = cpu_to_le16(key[i]); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, + offset + (i * 2), value); + + if (!basic_wep) + continue; + + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, + offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE, + value); + } +} + +static void keymac_write(struct bcm43xx_private *bcm, + u8 index, const u32 *addr) +{ + /* for keys 0-3 there is no associated mac address */ + if (index < 4) + return; + + index -= 4; + if (bcm->current_core->rev >= 5) { + bcm43xx_shm_write32(bcm, + BCM43xx_SHM_HWMAC, + index * 2, + cpu_to_be32(*addr)); + bcm43xx_shm_write16(bcm, + BCM43xx_SHM_HWMAC, + (index * 2) + 1, + cpu_to_be16(*((u16 *)(addr + 1)))); + } else { + if (index < 8) { + TODO(); /* Put them in the macaddress filter */ + } else { + TODO(); + /* Put them BCM43xx_SHM_SHARED, stating index 0x0120. + Keep in mind to update the count of keymacs in 0x003E as well! */ + } + } +} + +static int bcm43xx_key_write(struct bcm43xx_private *bcm, + u8 index, u8 algorithm, + const u8 *_key, int key_len, + const u8 *mac_addr) +{ + u8 key[BCM43xx_SEC_KEYSIZE] = { 0 }; + + if (index >= ARRAY_SIZE(bcm->key)) + return -EINVAL; + if (key_len > ARRAY_SIZE(key)) + return -EINVAL; + if (algorithm < 1 || algorithm > 5) + return -EINVAL; + + memcpy(key, _key, key_len); + key_write(bcm, index, algorithm, (const u16 *)key); + keymac_write(bcm, index, (const u32 *)mac_addr); + + bcm->key[index].algorithm = algorithm; + + return 0; +} + +static void bcm43xx_clear_keys(struct bcm43xx_private *bcm) +{ + static const u32 zero_mac[2] = { 0 }; + unsigned int i,j, nr_keys = 54; + u16 offset; + + if (bcm->current_core->rev < 5) + nr_keys = 16; + assert(nr_keys <= ARRAY_SIZE(bcm->key)); + + for (i = 0; i < nr_keys; i++) { + bcm->key[i].enabled = 0; + /* returns for i < 4 immediately */ + keymac_write(bcm, i, zero_mac); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, + 0x100 + (i * 2), 0x0000); + for (j = 0; j < 8; j++) { + offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, + offset, 0x0000); + } + } + dprintk(KERN_INFO PFX "Keys cleared\n"); +} + +/* Puts the index of the current core into user supplied core variable. + * This function reads the value from the device. + * Almost always you don't want to call this, but use bcm->current_core + */ +static inline +int _get_current_core(struct bcm43xx_private *bcm, int *core) +{ + int err; + + err = bcm43xx_pci_read_config32(bcm, BCM43xx_REG_ACTIVE_CORE, core); + if (unlikely(err)) { + dprintk(KERN_ERR PFX "BCM43xx_REG_ACTIVE_CORE read failed!\n"); + return -ENODEV; + } + *core = (*core - 0x18000000) / 0x1000; + + return 0; +} + +/* Lowlevel core-switch function. This is only to be used in + * bcm43xx_switch_core() and bcm43xx_probe_cores() + */ +static int _switch_core(struct bcm43xx_private *bcm, int core) +{ + int err; + int attempts = 0; + int current_core = -1; + + assert(core >= 0); + + err = _get_current_core(bcm, ¤t_core); + if (unlikely(err)) + goto out; + + /* Write the computed value to the register. This doesn't always + succeed so we retry BCM43xx_SWITCH_CORE_MAX_RETRIES times */ + while (current_core != core) { + if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES)) { + err = -ENODEV; + printk(KERN_ERR PFX + "unable to switch to core %u, retried %i times\n", + core, attempts); + goto out; + } + err = bcm43xx_pci_write_config32(bcm, BCM43xx_REG_ACTIVE_CORE, + (core * 0x1000) + 0x18000000); + if (unlikely(err)) { + dprintk(KERN_ERR PFX "BCM43xx_REG_ACTIVE_CORE write failed!\n"); + continue; + } + _get_current_core(bcm, ¤t_core); +#ifdef CONFIG_BCM947XX + if (bcm->pci_dev->bus->number == 0) + bcm->current_core_offset = 0x1000 * core; + else + bcm->current_core_offset = 0; +#endif + } + + assert(err == 0); +out: + return err; +} + +int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core) +{ + int err; + + if (!new_core) + return 0; + + if (!(new_core->flags & BCM43xx_COREFLAG_AVAILABLE)) + return -ENODEV; + if (bcm->current_core == new_core) + return 0; + err = _switch_core(bcm, new_core->index); + if (!err) + bcm->current_core = new_core; + + return err; +} + +static inline int bcm43xx_core_enabled(struct bcm43xx_private *bcm) +{ + u32 value; + + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET + | BCM43xx_SBTMSTATELOW_REJECT; + + return (value == BCM43xx_SBTMSTATELOW_CLOCK); +} + +/* disable current core */ +static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags) +{ + u32 sbtmstatelow; + u32 sbtmstatehigh; + int i; + + /* fetch sbtmstatelow from core information registers */ + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + + /* core is already in reset */ + if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET) + goto out; + + if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) { + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | + BCM43xx_SBTMSTATELOW_REJECT; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + + for (i = 0; i < 1000; i++) { + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) { + i = -1; + break; + } + udelay(10); + } + if (i != -1) { + printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n"); + return -EBUSY; + } + + for (i = 0; i < 1000; i++) { + sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); + if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) { + i = -1; + break; + } + udelay(10); + } + if (i != -1) { + printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n"); + return -EBUSY; + } + + sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | + BCM43xx_SBTMSTATELOW_REJECT | + BCM43xx_SBTMSTATELOW_RESET | + BCM43xx_SBTMSTATELOW_CLOCK | + core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(10); + } + + sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET | + BCM43xx_SBTMSTATELOW_REJECT | + core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + +out: + bcm->current_core->flags &= ~ BCM43xx_COREFLAG_ENABLED; + return 0; +} + +/* enable (reset) current core */ +static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags) +{ + u32 sbtmstatelow; + u32 sbtmstatehigh; + u32 sbimstate; + int err; + + err = bcm43xx_core_disable(bcm, core_flags); + if (err) + goto out; + + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | + BCM43xx_SBTMSTATELOW_RESET | + BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | + core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + + sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); + if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) { + sbtmstatehigh = 0x00000000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh); + } + + sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE); + if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) { + sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT); + bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate); + } + + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | + BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | + core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + + sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + + bcm->current_core->flags |= BCM43xx_COREFLAG_ENABLED; + assert(err == 0); +out: + return err; +} + +/* http://bcm-specs.sipsolutions.net/80211CoreReset */ +void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) +{ + u32 flags = 0x00040000; + + if ((bcm43xx_core_enabled(bcm)) && (!bcm->pio_mode)) { +//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here? +#ifndef CONFIG_BCM947XX + /* reset all used DMA controllers. */ + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE); + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE); + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE); + bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); + bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE); + if (bcm->current_core->rev < 5) + bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); +#endif + } + if (bcm->shutting_down) { + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); + } else { + if (connect_phy) + flags |= 0x20000000; + bcm43xx_phy_connect(bcm, connect_phy); + bcm43xx_core_enable(bcm, flags); + bcm43xx_write16(bcm, 0x03E6, 0x0000); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + | BCM43xx_SBF_400); + } +} + +static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm) +{ + bcm43xx_radio_turn_off(bcm); + bcm43xx_write16(bcm, 0x03E6, 0x00F4); + bcm43xx_core_disable(bcm, 0); +} + +/* Mark the current 80211 core inactive. + * "active_80211_core" is the other 80211 core, which is used. + */ +static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm, + struct bcm43xx_coreinfo *active_80211_core) +{ + u32 sbtmstatelow; + struct bcm43xx_coreinfo *old_core; + int err = 0; + + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + bcm43xx_radio_turn_off(bcm); + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + sbtmstatelow &= ~0x200a0000; + sbtmstatelow |= 0xa0000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + sbtmstatelow &= ~0xa0000; + sbtmstatelow |= 0x80000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + udelay(1); + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, active_80211_core); + if (err) + goto out; + sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + sbtmstatelow &= ~0x20000000; + sbtmstatelow |= 0x20000000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); + err = bcm43xx_switch_core(bcm, old_core); + } + +out: + return err; +} + +static inline void handle_irq_transmit_status(struct bcm43xx_private *bcm) +{ + u32 v0, v1; + u16 tmp; + struct bcm43xx_xmitstatus stat; + + assert(bcm->current_core->id == BCM43xx_COREID_80211); + assert(bcm->current_core->rev >= 5); + + while (1) { + v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0); + if (!v0) + break; + v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1); + + stat.cookie = (v0 >> 16) & 0x0000FFFF; + tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1)); + stat.flags = tmp & 0xFF; + stat.cnt1 = (tmp & 0x0F00) >> 8; + stat.cnt2 = (tmp & 0xF000) >> 12; + stat.seq = (u16)(v1 & 0xFFFF); + stat.unknown = (u16)((v1 >> 16) & 0xFF); + + bcm43xx_debugfs_log_txstat(bcm, &stat); + + if (stat.flags & BCM43xx_TXSTAT_FLAG_IGNORE) + continue; + if (!(stat.flags & BCM43xx_TXSTAT_FLAG_ACK)) { + //TODO: packet was not acked (was lost) + } + //TODO: There are more (unknown) flags to test. see bcm43xx_main.h + + if (bcm->pio_mode) + bcm43xx_pio_handle_xmitstatus(bcm, &stat); + else + bcm43xx_dma_handle_xmitstatus(bcm, &stat); + } +} + +static inline void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm) +{ + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4)); + assert(bcm->noisecalc.core_at_start == bcm->current_core); + assert(bcm->noisecalc.channel_at_start == bcm->current_core->radio->channel); +} + +static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm) +{ + /* Top half of Link Quality calculation. */ + + if (bcm->noisecalc.calculation_running) + return; + bcm->noisecalc.core_at_start = bcm->current_core; + bcm->noisecalc.channel_at_start = bcm->current_core->radio->channel; + bcm->noisecalc.calculation_running = 1; + bcm->noisecalc.nr_samples = 0; + + bcm43xx_generate_noise_sample(bcm); +} + +static inline void handle_irq_noise(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 tmp; + u8 noise[4]; + u8 i, j; + s32 average; + + /* Bottom half of Link Quality calculation. */ + + assert(bcm->noisecalc.calculation_running); + if (bcm->noisecalc.core_at_start != bcm->current_core || + bcm->noisecalc.channel_at_start != radio->channel) + goto drop_calculation; + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408); + noise[0] = (tmp & 0x00FF); + noise[1] = (tmp & 0xFF00) >> 8; + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A); + noise[2] = (tmp & 0x00FF); + noise[3] = (tmp & 0xFF00) >> 8; + if (noise[0] == 0x7F || noise[1] == 0x7F || + noise[2] == 0x7F || noise[3] == 0x7F) + goto generate_new; + + /* Get the noise samples. */ + assert(bcm->noisecalc.nr_samples <= 8); + i = bcm->noisecalc.nr_samples; + noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); + noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); + noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); + noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1); + bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]]; + bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]]; + bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]]; + bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]]; + bcm->noisecalc.nr_samples++; + if (bcm->noisecalc.nr_samples == 8) { + /* Calculate the Link Quality by the noise samples. */ + average = 0; + for (i = 0; i < 8; i++) { + for (j = 0; j < 4; j++) + average += bcm->noisecalc.samples[i][j]; + } + average /= (8 * 4); + average *= 125; + average += 64; + average /= 128; + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C); + tmp = (tmp / 128) & 0x1F; + if (tmp >= 8) + average += 2; + else + average -= 25; + if (tmp == 8) + average -= 72; + else + average -= 48; + + if (average > -65) + bcm->stats.link_quality = 0; + else if (average > -75) + bcm->stats.link_quality = 1; + else if (average > -85) + bcm->stats.link_quality = 2; + else + bcm->stats.link_quality = 3; +// dprintk(KERN_INFO PFX "Link Quality: %u (avg was %d)\n", bcm->stats.link_quality, average); +drop_calculation: + bcm->noisecalc.calculation_running = 0; + return; + } +generate_new: + bcm43xx_generate_noise_sample(bcm); +} + +static inline +void handle_irq_ps(struct bcm43xx_private *bcm) +{ + if (bcm->ieee->iw_mode == IW_MODE_MASTER) { + ///TODO: PS TBTT + } else { + if (1/*FIXME: the last PSpoll frame was sent successfully */) + bcm43xx_power_saving_ctl_bits(bcm, -1, -1); + } + if (bcm->ieee->iw_mode == IW_MODE_ADHOC) + bcm->reg124_set_0x4 = 1; + //FIXME else set to false? +} + +static inline +void handle_irq_reg124(struct bcm43xx_private *bcm) +{ + if (!bcm->reg124_set_0x4) + return; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) + | 0x4); + //FIXME: reset reg124_set_0x4 to false? +} + +static inline +void handle_irq_pmq(struct bcm43xx_private *bcm) +{ + u32 tmp; + + //TODO: AP mode. + + while (1) { + tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS); + if (!(tmp & 0x00000008)) + break; + } + /* 16bit write is odd, but correct. */ + bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002); +} + +static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm, + u16 ram_offset, u16 shm_size_offset) +{ + u32 value; + u16 size = 0; + + /* Timestamp. */ + //FIXME: assumption: The chip sets the timestamp + value = 0; + bcm43xx_ram_write(bcm, ram_offset++, value); + bcm43xx_ram_write(bcm, ram_offset++, value); + size += 8; + + /* Beacon Interval / Capability Information */ + value = 0x0000;//FIXME: Which interval? + value |= (1 << 0) << 16; /* ESS */ + value |= (1 << 2) << 16; /* CF Pollable */ //FIXME? + value |= (1 << 3) << 16; /* CF Poll Request */ //FIXME? + if (!bcm->ieee->open_wep) + value |= (1 << 4) << 16; /* Privacy */ + bcm43xx_ram_write(bcm, ram_offset++, value); + size += 4; + + /* SSID */ + //TODO + + /* FH Parameter Set */ + //TODO + + /* DS Parameter Set */ + //TODO + + /* CF Parameter Set */ + //TODO + + /* TIM */ + //TODO + + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size); +} + +static inline +void handle_irq_beacon(struct bcm43xx_private *bcm) +{ + u32 status; + + bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON; + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD); + + if ((status & 0x1) && (status & 0x2)) { + /* ACK beacon IRQ. */ + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, + BCM43xx_IRQ_BEACON); + bcm->irq_savedstate |= BCM43xx_IRQ_BEACON; + return; + } + if (!(status & 0x1)) { + bcm43xx_generate_beacon_template(bcm, 0x68, 0x18); + status |= 0x1; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status); + } + if (!(status & 0x2)) { + bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A); + status |= 0x2; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status); + } +} + +/* Debug helper for irq bottom-half to print all reason registers. */ +#define bcmirq_print_reasons(description) \ + do { \ + dprintkl(KERN_ERR PFX description "\n" \ + KERN_ERR PFX " Generic Reason: 0x%08x\n" \ + KERN_ERR PFX " DMA reasons: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n" \ + KERN_ERR PFX " DMA TX status: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", \ + reason, \ + dma_reason[0], dma_reason[1], \ + dma_reason[2], dma_reason[3], \ + bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_BASE + BCM43xx_DMA_TX_STATUS), \ + bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_BASE + BCM43xx_DMA_TX_STATUS), \ + bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_BASE + BCM43xx_DMA_TX_STATUS), \ + bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_BASE + BCM43xx_DMA_TX_STATUS)); \ + } while (0) + +/* Interrupt handler bottom-half */ +static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) +{ + u32 reason; + u32 dma_reason[4]; + int activity = 0; + unsigned long flags; + +#ifdef CONFIG_BCM43XX_DEBUG + u32 _handled = 0x00000000; +# define bcmirq_handled(irq) do { _handled |= (irq); } while (0) +#else +# define bcmirq_handled(irq) do { /* nothing */ } while (0) +#endif /* CONFIG_BCM43XX_DEBUG*/ + + spin_lock_irqsave(&bcm->lock, flags); + reason = bcm->irq_reason; + dma_reason[0] = bcm->dma_reason[0]; + dma_reason[1] = bcm->dma_reason[1]; + dma_reason[2] = bcm->dma_reason[2]; + dma_reason[3] = bcm->dma_reason[3]; + + if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) { + /* TX error. We get this when Template Ram is written in wrong endianess + * in dummy_tx(). We also get this if something is wrong with the TX header + * on DMA or PIO queues. + * Maybe we get this in other error conditions, too. + */ + bcmirq_print_reasons("XMIT ERROR"); + bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR); + } + + if (reason & BCM43xx_IRQ_PS) { + handle_irq_ps(bcm); + bcmirq_handled(BCM43xx_IRQ_PS); + } + + if (reason & BCM43xx_IRQ_REG124) { + handle_irq_reg124(bcm); + bcmirq_handled(BCM43xx_IRQ_REG124); + } + + if (reason & BCM43xx_IRQ_BEACON) { + if (bcm->ieee->iw_mode == IW_MODE_MASTER) + handle_irq_beacon(bcm); + bcmirq_handled(BCM43xx_IRQ_BEACON); + } + + if (reason & BCM43xx_IRQ_PMQ) { + handle_irq_pmq(bcm); + bcmirq_handled(BCM43xx_IRQ_PMQ); + } + + if (reason & BCM43xx_IRQ_SCAN) { + /*TODO*/ + //bcmirq_handled(BCM43xx_IRQ_SCAN); + } + + if (reason & BCM43xx_IRQ_NOISE) { + handle_irq_noise(bcm); + bcmirq_handled(BCM43xx_IRQ_NOISE); + } + + /* Check the DMA reason registers for received data. */ + assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE)); + assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE)); + if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) { + if (bcm->pio_mode) + bcm43xx_pio_rx(bcm->current_core->pio->queue0); + else + bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0); + activity = 1; + } + if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { + if (likely(bcm->current_core->rev < 5)) { + if (bcm->pio_mode) + bcm43xx_pio_rx(bcm->current_core->pio->queue3); + else + bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1); + activity = 1; + } else + assert(0); + } + bcmirq_handled(BCM43xx_IRQ_RX); + + if (reason & BCM43xx_IRQ_XMIT_STATUS) { + if (bcm->current_core->rev >= 5) { + handle_irq_transmit_status(bcm); + activity = 1; + } + //TODO: In AP mode, this also causes sending of powersave responses. + bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS); + } + + /* We get spurious IRQs, althought they are masked. + * Assume they are void and ignore them. + */ + bcmirq_handled(~(bcm->irq_savedstate)); + /* IRQ_PIO_WORKAROUND is handled in the top-half. */ + bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND); +#ifdef CONFIG_BCM43XX_DEBUG + if (unlikely(reason & ~_handled)) { + printkl(KERN_WARNING PFX + "Unhandled IRQ! Reason: 0x%08x, Unhandled: 0x%08x, " + "DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", + reason, (reason & ~_handled), + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3]); + } +#endif +#undef bcmirq_handled + + if (!modparam_noleds) + bcm43xx_leds_update(bcm, activity); + bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); + spin_unlock_irqrestore(&bcm->lock, flags); +} + +#undef bcmirq_print_reasons + +static inline +void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, + u32 reason, u32 mask) +{ + bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) + & 0x0001dc00; + bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON) + & 0x0000dc00; + bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON) + & 0x0000dc00; + bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) + & 0x0001dc00; + + if ((bcm->pio_mode) && + (bcm->current_core->rev < 3) && + (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) { + /* Apply a PIO specific workaround to the dma_reasons */ + +#define apply_pio_workaround(BASE, QNUM) \ + do { \ + if (bcm43xx_read16(bcm, BASE + BCM43xx_PIO_RXCTL) & BCM43xx_PIO_RXCTL_DATAAVAILABLE) \ + bcm->dma_reason[QNUM] |= 0x00010000; \ + else \ + bcm->dma_reason[QNUM] &= ~0x00010000; \ + } while (0) + + apply_pio_workaround(BCM43xx_MMIO_PIO1_BASE, 0); + apply_pio_workaround(BCM43xx_MMIO_PIO2_BASE, 1); + apply_pio_workaround(BCM43xx_MMIO_PIO3_BASE, 2); + apply_pio_workaround(BCM43xx_MMIO_PIO4_BASE, 3); + +#undef apply_pio_workaround + } + + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, + reason & mask); + + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON, + bcm->dma_reason[0]); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON, + bcm->dma_reason[1]); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON, + bcm->dma_reason[2]); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON, + bcm->dma_reason[3]); +} + +/* Interrupt handler top-half */ +static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + struct bcm43xx_private *bcm = dev_id; + u32 reason, mask; + + if (!bcm) + return IRQ_NONE; + + spin_lock(&bcm->lock); + + reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (reason == 0xffffffff) { + /* irq not for us (shared irq) */ + spin_unlock(&bcm->lock); + return IRQ_NONE; + } + mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); + if (!(reason & mask)) { + spin_unlock(&bcm->lock); + return IRQ_HANDLED; + } + + bcm43xx_interrupt_ack(bcm, reason, mask); + + /* disable all IRQs. They are enabled again in the bottom half. */ + bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + + /* save the reason code and call our bottom half. */ + bcm->irq_reason = reason; + tasklet_schedule(&bcm->isr_tasklet); + + spin_unlock(&bcm->lock); + + return IRQ_HANDLED; +} + +static void bcm43xx_release_firmware(struct bcm43xx_private *bcm) +{ + if (bcm->firmware_norelease) + return; /* Suspending or controller reset. */ + release_firmware(bcm->ucode); + bcm->ucode = NULL; + release_firmware(bcm->pcm); + bcm->pcm = NULL; + release_firmware(bcm->initvals0); + bcm->initvals0 = NULL; + release_firmware(bcm->initvals1); + bcm->initvals1 = NULL; +} + +static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u8 rev = bcm->current_core->rev; + int err = 0; + int nr; + char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; + + if (!bcm->ucode) { + snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", + (rev >= 5 ? 5 : rev), + modparam_fwpostfix); + err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev); + if (err) { + printk(KERN_ERR PFX + "Error: Microcode \"%s\" not available or load failed.\n", + buf); + goto error; + } + } + + if (!bcm->pcm) { + snprintf(buf, ARRAY_SIZE(buf), + "bcm43xx_pcm%d%s.fw", + (rev < 5 ? 4 : 5), + modparam_fwpostfix); + err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev); + if (err) { + printk(KERN_ERR PFX + "Error: PCM \"%s\" not available or load failed.\n", + buf); + goto error; + } + } + + if (!bcm->initvals0) { + if (rev == 2 || rev == 4) { + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + nr = 3; + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + nr = 1; + break; + default: + goto err_noinitval; + } + + } else if (rev >= 5) { + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + nr = 7; + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + nr = 5; + break; + default: + goto err_noinitval; + } + } else + goto err_noinitval; + snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", + nr, modparam_fwpostfix); + + err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev); + if (err) { + printk(KERN_ERR PFX + "Error: InitVals \"%s\" not available or load failed.\n", + buf); + goto error; + } + if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) { + printk(KERN_ERR PFX "InitVals fileformat error.\n"); + goto error; + } + } + + if (!bcm->initvals1) { + if (rev >= 5) { + u32 sbtmstatehigh; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); + if (sbtmstatehigh & 0x00010000) + nr = 9; + else + nr = 10; + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + nr = 6; + break; + default: + goto err_noinitval; + } + snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", + nr, modparam_fwpostfix); + + err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev); + if (err) { + printk(KERN_ERR PFX + "Error: InitVals \"%s\" not available or load failed.\n", + buf); + goto error; + } + if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) { + printk(KERN_ERR PFX "InitVals fileformat error.\n"); + goto error; + } + } + } + +out: + return err; +error: + bcm43xx_release_firmware(bcm); + goto out; +err_noinitval: + printk(KERN_ERR PFX "Error: No InitVals available!\n"); + err = -ENOENT; + goto error; +} + +static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) +{ + const u32 *data; + unsigned int i, len; + +#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT + bcm43xx_mmioprint_enable(bcm); +#else + bcm43xx_mmioprint_disable(bcm); +#endif + + /* Upload Microcode. */ + data = (u32 *)(bcm->ucode->data); + len = bcm->ucode->size / sizeof(u32); + bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); + for (i = 0; i < len; i++) { + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, + be32_to_cpu(data[i])); + udelay(10); + } + + /* Upload PCM data. */ + data = (u32 *)(bcm->pcm->data); + len = bcm->pcm->size / sizeof(u32); + bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); + bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb); + for (i = 0; i < len; i++) { + bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, + be32_to_cpu(data[i])); + udelay(10); + } + +#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT + bcm43xx_mmioprint_disable(bcm); +#else + bcm43xx_mmioprint_enable(bcm); +#endif +} + +static void bcm43xx_write_initvals(struct bcm43xx_private *bcm, + const struct bcm43xx_initval *data, + const unsigned int len) +{ + u16 offset, size; + u32 value; + unsigned int i; + + for (i = 0; i < len; i++) { + offset = be16_to_cpu(data[i].offset); + size = be16_to_cpu(data[i].size); + value = be32_to_cpu(data[i].value); + + if (size == 2) + bcm43xx_write16(bcm, offset, value); + else if (size == 4) + bcm43xx_write32(bcm, offset, value); + else + printk(KERN_ERR PFX "InitVals fileformat error.\n"); + } +} + +static void bcm43xx_upload_initvals(struct bcm43xx_private *bcm) +{ +#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT + bcm43xx_mmioprint_enable(bcm); +#else + bcm43xx_mmioprint_disable(bcm); +#endif + + bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, + bcm->initvals0->size / sizeof(struct bcm43xx_initval)); + if (bcm->initvals1) { + bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, + bcm->initvals1->size / sizeof(struct bcm43xx_initval)); + } + +#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT + bcm43xx_mmioprint_disable(bcm); +#else + bcm43xx_mmioprint_enable(bcm); +#endif +} + +static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) +{ + int res; + unsigned int i; + u32 data; + + bcm->irq = bcm->pci_dev->irq; +#ifdef CONFIG_BCM947XX + if (bcm->pci_dev->bus->number == 0) { + struct pci_dev *d = NULL; + /* FIXME: we will probably need more device IDs here... */ + d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL); + if (d != NULL) { + bcm->irq = d->irq; + } + } +#endif + res = request_irq(bcm->irq, bcm43xx_interrupt_handler, + SA_SHIRQ, DRV_NAME, bcm); + if (res) { + printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); + return -EFAULT; + } + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); + i = 0; + while (1) { + data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (data == BCM43xx_IRQ_READY) + break; + i++; + if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) { + printk(KERN_ERR PFX "Card IRQ register not responding. " + "Giving up.\n"); + free_irq(bcm->irq, bcm); + return -ENODEV; + } + udelay(10); + } + // dummy read + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + + return 0; +} + +/* Switch to the core used to write the GPIO register. + * This is either the ChipCommon, or the PCI core. + */ +static inline int switch_to_gpio_core(struct bcm43xx_private *bcm) +{ + int err; + + /* Where to find the GPIO register depends on the chipset. + * If it has a ChipCommon, its register at offset 0x6c is the GPIO + * control register. Otherwise the register at offset 0x6c in the + * PCI core is the GPIO control register. + */ + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err == -ENODEV) { + err = bcm43xx_switch_core(bcm, &bcm->core_pci); + if (err == -ENODEV) { + printk(KERN_ERR PFX "gpio error: " + "Neither ChipCommon nor PCI core available!\n"); + return -ENODEV; + } else if (err != 0) + return -ENODEV; + } else if (err != 0) + return -ENODEV; + + return 0; +} + +/* Initialize the GPIOs + * http://bcm-specs.sipsolutions.net/GPIO + */ +static int bcm43xx_gpio_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_coreinfo *old_core; + int err; + u32 mask, value; + + value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value &= ~0xc000; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value); + + mask = 0x0000001F; + value = 0x0000000F; + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL) & 0xFFF0); + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F); + + old_core = bcm->current_core; + + err = switch_to_gpio_core(bcm); + if (err) + return err; + + if (bcm->current_core->rev >= 2){ + mask |= 0x10; + value |= 0x10; + } + if (bcm->chip_id == 0x4301) { + mask |= 0x60; + value |= 0x60; + } + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { + mask |= 0x200; + value |= 0x200; + } + + bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, + (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | value); + + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + + return 0; +} + +/* Turn off all GPIO stuff. Call this on module unload, for example. */ +static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm) +{ + struct bcm43xx_coreinfo *old_core; + int err; + + old_core = bcm->current_core; + err = switch_to_gpio_core(bcm); + if (err) + return err; + bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000); + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + + return 0; +} + +/* http://bcm-specs.sipsolutions.net/EnableMac */ +void bcm43xx_mac_enable(struct bcm43xx_private *bcm) +{ + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + | BCM43xx_SBF_MAC_ENABLED); + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY); + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ + bcm43xx_power_saving_ctl_bits(bcm, -1, -1); +} + +/* http://bcm-specs.sipsolutions.net/SuspendMAC */ +void bcm43xx_mac_suspend(struct bcm43xx_private *bcm) +{ + int i; + u32 tmp; + + bcm43xx_power_saving_ctl_bits(bcm, -1, 1); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + & ~BCM43xx_SBF_MAC_ENABLED); + bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ + for (i = 1000; i > 0; i--) { + tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (tmp & BCM43xx_IRQ_READY) { + i = -1; + break; + } + udelay(10); + } + if (!i) + printkl(KERN_ERR PFX "Failed to suspend mac!\n"); +} + +void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, + int iw_mode) +{ + unsigned long flags; + u32 status; + + spin_lock_irqsave(&bcm->ieee->lock, flags); + bcm->ieee->iw_mode = iw_mode; + spin_unlock_irqrestore(&bcm->ieee->lock, flags); + if (iw_mode == IW_MODE_MONITOR) + bcm->net_dev->type = ARPHRD_IEEE80211; + else + bcm->net_dev->type = ARPHRD_ETHER; + + if (!bcm->initialized) + return; + + bcm43xx_mac_suspend(bcm); + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + /* Reset status to infrastructured mode */ + status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR); + /*FIXME: We actually set promiscuous mode as well, until we don't + * get the HW mac filter working */ + status |= BCM43xx_SBF_MODE_NOTADHOC | BCM43xx_SBF_MODE_PROMISC; + + switch (iw_mode) { + case IW_MODE_MONITOR: + status |= (BCM43xx_SBF_MODE_PROMISC | + BCM43xx_SBF_MODE_MONITOR); + break; + case IW_MODE_ADHOC: + status &= ~BCM43xx_SBF_MODE_NOTADHOC; + break; + case IW_MODE_MASTER: + case IW_MODE_SECOND: + case IW_MODE_REPEAT: + /* TODO: No AP/Repeater mode for now :-/ */ + TODO(); + break; + case IW_MODE_INFRA: + /* nothing to be done here... */ + break; + default: + printk(KERN_ERR PFX "Unknown iwmode %d\n", iw_mode); + } + + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + bcm43xx_mac_enable(bcm); +} + +/* This is the opposite of bcm43xx_chip_init() */ +static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm) +{ + bcm43xx_radio_turn_off(bcm); + if (!modparam_noleds) + bcm43xx_leds_exit(bcm); + bcm43xx_gpio_cleanup(bcm); + free_irq(bcm->irq, bcm); + bcm43xx_release_firmware(bcm); +} + +/* Initialize the chip + * http://bcm-specs.sipsolutions.net/ChipInit + */ +static int bcm43xx_chip_init(struct bcm43xx_private *bcm) +{ + int err; + int iw_mode = bcm->ieee->iw_mode; + int tmp; + u32 value32; + u16 value16; + + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + BCM43xx_SBF_CORE_READY + | BCM43xx_SBF_400); + + err = bcm43xx_request_firmware(bcm); + if (err) + goto out; + bcm43xx_upload_microcode(bcm); + + err = bcm43xx_initialize_irq(bcm); + if (err) + goto out; + + err = bcm43xx_gpio_init(bcm); + if (err) + goto err_free_irq; + + bcm43xx_upload_initvals(bcm); + bcm43xx_radio_turn_on(bcm); + + if (modparam_noleds) + bcm43xx_leds_turn_off(bcm); + else + bcm43xx_leds_update(bcm, 0); + + bcm43xx_write16(bcm, 0x03E6, 0x0000); + err = bcm43xx_phy_init(bcm); + if (err) + goto err_radio_off; + + /* Select initial Interference Mitigation. */ + tmp = bcm->current_core->radio->interfmode; + bcm->current_core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; + bcm43xx_radio_set_interference_mitigation(bcm, tmp); + + bcm43xx_phy_set_antenna_diversity(bcm); + bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT); + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) { + value16 = bcm43xx_read16(bcm, 0x005E); + value16 |= 0x0004; + bcm43xx_write16(bcm, 0x005E, value16); + } + bcm43xx_write32(bcm, 0x0100, 0x01000000); + if (bcm->current_core->rev < 5) + bcm43xx_write32(bcm, 0x010C, 0x01000000); + + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value32 &= ~ BCM43xx_SBF_MODE_NOTADHOC; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value32 |= BCM43xx_SBF_MODE_NOTADHOC; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); + /*FIXME: For now, use promiscuous mode at all times; otherwise we don't + get broadcast or multicast packets */ + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value32 |= BCM43xx_SBF_MODE_PROMISC; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); + + if (iw_mode == IW_MODE_MONITOR) { + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value32 |= BCM43xx_SBF_MODE_PROMISC; + value32 |= BCM43xx_SBF_MODE_MONITOR; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); + } + value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value32 |= 0x100000; //FIXME: What's this? Is this correct? + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); + + if (bcm->pio_mode) { + bcm43xx_write32(bcm, 0x0210, 0x00000100); + bcm43xx_write32(bcm, 0x0230, 0x00000100); + bcm43xx_write32(bcm, 0x0250, 0x00000100); + bcm43xx_write32(bcm, 0x0270, 0x00000100); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0034, 0x0000); + } + + /* Probe Response Timeout value */ + /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */ + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000); + + if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) { + if ((bcm->chip_id == 0x4306) && (bcm->chip_rev == 3)) + bcm43xx_write16(bcm, 0x0612, 0x0064); + else + bcm43xx_write16(bcm, 0x0612, 0x0032); + } else + bcm43xx_write16(bcm, 0x0612, 0x0002); + + if (bcm->current_core->rev < 3) { + bcm43xx_write16(bcm, 0x060E, 0x0000); + bcm43xx_write16(bcm, 0x0610, 0x8000); + bcm43xx_write16(bcm, 0x0604, 0x0000); + bcm43xx_write16(bcm, 0x0606, 0x0200); + } else { + bcm43xx_write32(bcm, 0x0188, 0x80000000); + bcm43xx_write32(bcm, 0x018C, 0x02000000); + } + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0x00004000); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_IRQ_MASK, 0x0001DC00); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_IRQ_MASK, 0x0000DC00); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_IRQ_MASK, 0x0000DC00); + bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_IRQ_MASK, 0x0001DC00); + + value32 = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + value32 |= 0x00100000; + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, value32); + + bcm43xx_write16(bcm, BCM43xx_MMIO_POWERUP_DELAY, bcm43xx_pctl_powerup_delay(bcm)); + + assert(err == 0); + dprintk(KERN_INFO PFX "Chip initialized\n"); +out: + return err; + +err_radio_off: + bcm43xx_radio_turn_off(bcm); + bcm43xx_gpio_cleanup(bcm); +err_free_irq: + free_irq(bcm->irq, bcm); + goto out; +} + +/* Validate chip access + * http://bcm-specs.sipsolutions.net/ValidateChipAccess */ +static int bcm43xx_validate_chip(struct bcm43xx_private *bcm) +{ + int err = -ENODEV; + u32 value; + u32 shm_backup; + + shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA); + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA) { + printk(KERN_ERR PFX "Error: SHM mismatch (1) validating chip\n"); + goto out; + } + + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55); + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55) { + printk(KERN_ERR PFX "Error: SHM mismatch (2) validating chip\n"); + goto out; + } + + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup); + + value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + if ((value | 0x80000000) != 0x80000400) { + printk(KERN_ERR PFX "Error: Bad Status Bitfield while validating chip\n"); + goto out; + } + + value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); + if (value != 0x00000000) { + printk(KERN_ERR PFX "Error: Bad interrupt reason code while validating chip\n"); + goto out; + } + + err = 0; +out: + return err; +} + +static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) +{ + int err, i; + int current_core; + u32 core_vendor, core_id, core_rev; + u32 sb_id_hi, chip_id_32 = 0; + u16 pci_device, chip_id_16; + u8 core_count; + + memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo)); + memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo)); + memset(&bcm->core_v90, 0, sizeof(struct bcm43xx_coreinfo)); + memset(&bcm->core_pcmcia, 0, sizeof(struct bcm43xx_coreinfo)); + memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo) + * BCM43xx_MAX_80211_CORES); + + memset(&bcm->phy, 0, sizeof(struct bcm43xx_phyinfo) + * BCM43xx_MAX_80211_CORES); + memset(&bcm->radio, 0, sizeof(struct bcm43xx_radioinfo) + * BCM43xx_MAX_80211_CORES); + + /* map core 0 */ + err = _switch_core(bcm, 0); + if (err) + goto out; + + /* fetch sb_id_hi from core information registers */ + sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI); + + core_id = (sb_id_hi & 0xFFF0) >> 4; + core_rev = (sb_id_hi & 0xF); + core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; + + /* if present, chipcommon is always core 0; read the chipid from it */ + if (core_id == BCM43xx_COREID_CHIPCOMMON) { + chip_id_32 = bcm43xx_read32(bcm, 0); + chip_id_16 = chip_id_32 & 0xFFFF; + bcm->core_chipcommon.flags |= BCM43xx_COREFLAG_AVAILABLE; + bcm->core_chipcommon.id = core_id; + bcm->core_chipcommon.rev = core_rev; + bcm->core_chipcommon.index = 0; + /* While we are at it, also read the capabilities. */ + bcm->chipcommon_capabilities = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_CAPABILITIES); + } else { + /* without a chipCommon, use a hard coded table. */ + pci_device = bcm->pci_dev->device; + if (pci_device == 0x4301) + chip_id_16 = 0x4301; + else if ((pci_device >= 0x4305) && (pci_device <= 0x4307)) + chip_id_16 = 0x4307; + else if ((pci_device >= 0x4402) && (pci_device <= 0x4403)) + chip_id_16 = 0x4402; + else if ((pci_device >= 0x4610) && (pci_device <= 0x4615)) + chip_id_16 = 0x4610; + else if ((pci_device >= 0x4710) && (pci_device <= 0x4715)) + chip_id_16 = 0x4710; +#ifdef CONFIG_BCM947XX + else if ((pci_device >= 0x4320) && (pci_device <= 0x4325)) + chip_id_16 = 0x4309; +#endif + else { + printk(KERN_ERR PFX "Could not determine Chip ID\n"); + return -ENODEV; + } + } + + /* ChipCommon with Core Rev >=4 encodes number of cores, + * otherwise consult hardcoded table */ + if ((core_id == BCM43xx_COREID_CHIPCOMMON) && (core_rev >= 4)) { + core_count = (chip_id_32 & 0x0F000000) >> 24; + } else { + switch (chip_id_16) { + case 0x4610: + case 0x4704: + case 0x4710: + core_count = 9; + break; + case 0x4310: + core_count = 8; + break; + case 0x5365: + core_count = 7; + break; + case 0x4306: + core_count = 6; + break; + case 0x4301: + case 0x4307: + core_count = 5; + break; + case 0x4402: + core_count = 3; + break; + default: + /* SOL if we get here */ + assert(0); + core_count = 1; + } + } + + bcm->chip_id = chip_id_16; + bcm->chip_rev = (chip_id_32 & 0x000f0000) >> 16; + + dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n", + bcm->chip_id, bcm->chip_rev); + dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count); + if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE) { + dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n", + core_id, core_rev, core_vendor, + bcm43xx_core_enabled(bcm) ? "enabled" : "disabled"); + } + + if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE) + current_core = 1; + else + current_core = 0; + for ( ; current_core < core_count; current_core++) { + struct bcm43xx_coreinfo *core; + + err = _switch_core(bcm, current_core); + if (err) + goto out; + /* Gather information */ + /* fetch sb_id_hi from core information registers */ + sb_id_hi = bcm43xx_read32(bcm, BCM43xx_CIR_SB_ID_HI); + + /* extract core_id, core_rev, core_vendor */ + core_id = (sb_id_hi & 0xFFF0) >> 4; + core_rev = (sb_id_hi & 0xF); + core_vendor = (sb_id_hi & 0xFFFF0000) >> 16; + + dprintk(KERN_INFO PFX "Core %d: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n", + current_core, core_id, core_rev, core_vendor, + bcm43xx_core_enabled(bcm) ? "enabled" : "disabled" ); + + core = NULL; + switch (core_id) { + case BCM43xx_COREID_PCI: + core = &bcm->core_pci; + if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { + printk(KERN_WARNING PFX "Multiple PCI cores found.\n"); + continue; + } + break; + case BCM43xx_COREID_V90: + core = &bcm->core_v90; + if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { + printk(KERN_WARNING PFX "Multiple V90 cores found.\n"); + continue; + } + break; + case BCM43xx_COREID_PCMCIA: + core = &bcm->core_pcmcia; + if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { + printk(KERN_WARNING PFX "Multiple PCMCIA cores found.\n"); + continue; + } + break; + case BCM43xx_COREID_ETHERNET: + core = &bcm->core_ethernet; + if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { + printk(KERN_WARNING PFX "Multiple Ethernet cores found.\n"); + continue; + } + break; + case BCM43xx_COREID_80211: + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + core = &(bcm->core_80211[i]); + if (!(core->flags & BCM43xx_COREFLAG_AVAILABLE)) + break; + core = NULL; + } + if (!core) { + printk(KERN_WARNING PFX "More than %d cores of type 802.11 found.\n", + BCM43xx_MAX_80211_CORES); + continue; + } + if (i != 0) { + /* More than one 80211 core is only supported + * by special chips. + * There are chips with two 80211 cores, but with + * dangling pins on the second core. Be careful + * and ignore these cores here. + */ + if (bcm->pci_dev->device != 0x4324) { + dprintk(KERN_INFO PFX "Ignoring additional 802.11 core.\n"); + continue; + } + } + switch (core_rev) { + case 2: + case 4: + case 5: + case 6: + case 7: + case 9: + break; + default: + printk(KERN_ERR PFX "Error: Unsupported 80211 core revision %u\n", + core_rev); + err = -ENODEV; + goto out; + } + core->phy = &bcm->phy[i]; + core->phy->antenna_diversity = 0xffff; + core->phy->savedpctlreg = 0xFFFF; + core->phy->minlowsig[0] = 0xFFFF; + core->phy->minlowsig[1] = 0xFFFF; + core->phy->minlowsigpos[0] = 0; + core->phy->minlowsigpos[1] = 0; + spin_lock_init(&core->phy->lock); + core->radio = &bcm->radio[i]; + core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; + core->radio->channel = 0xFF; + core->radio->initial_channel = 0xFF; + core->radio->lofcal = 0xFFFF; + core->radio->initval = 0xFFFF; + core->radio->nrssi[0] = -1000; + core->radio->nrssi[1] = -1000; + core->dma = &bcm->dma[i]; + core->pio = &bcm->pio[i]; + break; + case BCM43xx_COREID_CHIPCOMMON: + printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n"); + break; + default: + printk(KERN_WARNING PFX "Unknown core found (ID 0x%x)\n", core_id); + } + if (core) { + core->flags |= BCM43xx_COREFLAG_AVAILABLE; + core->id = core_id; + core->rev = core_rev; + core->index = current_core; + } + } + + if (!(bcm->core_80211[0].flags & BCM43xx_COREFLAG_AVAILABLE)) { + printk(KERN_ERR PFX "Error: No 80211 core found!\n"); + err = -ENODEV; + goto out; + } + + err = bcm43xx_switch_core(bcm, &bcm->core_80211[0]); + + assert(err == 0); +out: + return err; +} + +static void bcm43xx_gen_bssid(struct bcm43xx_private *bcm) +{ + const u8 *mac = (const u8*)(bcm->net_dev->dev_addr); + u8 *bssid = bcm->ieee->bssid; + + switch (bcm->ieee->iw_mode) { + case IW_MODE_ADHOC: + random_ether_addr(bssid); + break; + case IW_MODE_MASTER: + case IW_MODE_INFRA: + case IW_MODE_REPEAT: + case IW_MODE_SECOND: + case IW_MODE_MONITOR: + memcpy(bssid, mac, ETH_ALEN); + break; + default: + assert(0); + } +} + +static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm, + u16 rate, + int is_ofdm) +{ + u16 offset; + + if (is_ofdm) { + offset = 0x480; + offset += (bcm43xx_plcp_get_ratecode_ofdm(rate) & 0x000F) * 2; + } + else { + offset = 0x4C0; + offset += (bcm43xx_plcp_get_ratecode_cck(rate) & 0x000F) * 2; + } + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + 0x20, + bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, offset)); +} + +static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm) +{ + switch (bcm->current_core->phy->type) { + case BCM43xx_PHYTYPE_A: + case BCM43xx_PHYTYPE_G: + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_12MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_18MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_24MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_36MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_48MB, 1); + bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_54MB, 1); + case BCM43xx_PHYTYPE_B: + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_1MB, 0); + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_2MB, 0); + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_5MB, 0); + bcm43xx_rate_memory_write(bcm, IEEE80211_CCK_RATE_11MB, 0); + break; + default: + assert(0); + } +} + +static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm) +{ + bcm43xx_chip_cleanup(bcm); + bcm43xx_pio_free(bcm); + bcm43xx_dma_free(bcm); + + bcm->current_core->flags &= ~ BCM43xx_COREFLAG_INITIALIZED; +} + +/* http://bcm-specs.sipsolutions.net/80211Init */ +static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) +{ + u32 ucodeflags; + int err; + u32 sbimconfiglow; + u8 limit; + + if (bcm->chip_rev < 5) { + sbimconfiglow = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); + sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; + sbimconfiglow &= ~ BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; + if (bcm->bustype == BCM43xx_BUSTYPE_PCI) + sbimconfiglow |= 0x32; + else if (bcm->bustype == BCM43xx_BUSTYPE_SB) + sbimconfiglow |= 0x53; + else + assert(0); + bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, sbimconfiglow); + } + + bcm43xx_phy_calibrate(bcm); + err = bcm43xx_chip_init(bcm); + if (err) + goto out; + + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0016, bcm->current_core->rev); + ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET); + + if (0 /*FIXME: which condition has to be used here? */) + ucodeflags |= 0x00000010; + + /* HW decryption needs to be set now */ + ucodeflags |= 0x40000000; + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; + if (bcm->current_core->phy->rev == 1) + ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY; + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) + ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL; + } else if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) { + ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; + if ((bcm->current_core->phy->rev >= 2) && + (bcm->current_core->radio->version == 0x2050)) + ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY; + } + + if (ucodeflags != bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET)) { + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, ucodeflags); + } + + /* Short/Long Retry Limit. + * The retry-limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. + */ + limit = limit_value(modparam_short_retry, 0, 0xF); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0006, limit); + limit = limit_value(modparam_long_retry, 0, 0xF); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0007, limit); + + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0044, 3); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0046, 2); + + bcm43xx_rate_memory_init(bcm); + + /* Minimum Contention Window */ + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f); + else + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f); + /* Maximum Contention Window */ + bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); + + bcm43xx_gen_bssid(bcm); + bcm43xx_write_mac_bssid_templates(bcm); + + if (bcm->current_core->rev >= 5) + bcm43xx_write16(bcm, 0x043C, 0x000C); + + if (!bcm->pio_mode) { + err = bcm43xx_dma_init(bcm); + if (err) + goto err_chip_cleanup; + } else { + err = bcm43xx_pio_init(bcm); + if (err) + goto err_chip_cleanup; + } + bcm43xx_write16(bcm, 0x0612, 0x0050); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); + + bcm43xx_mac_enable(bcm); + bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); + + bcm->current_core->flags |= BCM43xx_COREFLAG_INITIALIZED; +out: + return err; + +err_chip_cleanup: + bcm43xx_chip_cleanup(bcm); + goto out; +} + +static int bcm43xx_chipset_attach(struct bcm43xx_private *bcm) +{ + int err; + u16 pci_status; + + err = bcm43xx_pctl_set_crystal(bcm, 1); + if (err) + goto out; + bcm43xx_pci_read_config16(bcm, PCI_STATUS, &pci_status); + bcm43xx_pci_write_config16(bcm, PCI_STATUS, pci_status & ~PCI_STATUS_SIG_TARGET_ABORT); + +out: + return err; +} + +static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm) +{ + bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); + bcm43xx_pctl_set_crystal(bcm, 0); +} + +static inline void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm, + u32 address, + u32 data) +{ + bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address); + bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data); +} + +static int bcm43xx_pcicore_commit_settings(struct bcm43xx_private *bcm) +{ + int err; + struct bcm43xx_coreinfo *old_core; + + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_pci); + if (err) + goto out; + + bcm43xx_pcicore_broadcast_value(bcm, 0xfd8, 0x00000000); + + bcm43xx_switch_core(bcm, old_core); + assert(err == 0); +out: + return err; +} + +/* Make an I/O Core usable. "core_mask" is the bitmask of the cores to enable. + * To enable core 0, pass a core_mask of 1<<0 + */ +static int bcm43xx_setup_backplane_pci_connection(struct bcm43xx_private *bcm, + u32 core_mask) +{ + u32 backplane_flag_nr; + u32 value; + struct bcm43xx_coreinfo *old_core; + int err = 0; + + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTPSFLAG); + backplane_flag_nr = value & BCM43xx_BACKPLANE_FLAG_NR_MASK; + + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_pci); + if (err) + goto out; + + if (bcm->core_pci.rev < 6) { + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBINTVEC); + value |= (1 << backplane_flag_nr); + bcm43xx_write32(bcm, BCM43xx_CIR_SBINTVEC, value); + } else { + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ICR, &value); + if (err) { + printk(KERN_ERR PFX "Error: ICR setup failure!\n"); + goto out_switch_back; + } + value |= core_mask << 8; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ICR, value); + if (err) { + printk(KERN_ERR PFX "Error: ICR setup failure!\n"); + goto out_switch_back; + } + } + + value = bcm43xx_read32(bcm, BCM43xx_PCICORE_SBTOPCI2); + value |= BCM43xx_SBTOPCI2_PREFETCH | BCM43xx_SBTOPCI2_BURST; + bcm43xx_write32(bcm, BCM43xx_PCICORE_SBTOPCI2, value); + + if (bcm->core_pci.rev < 5) { + value = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMCONFIGLOW); + value |= (2 << BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_SHIFT) + & BCM43xx_SBIMCONFIGLOW_SERVICE_TOUT_MASK; + value |= (3 << BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_SHIFT) + & BCM43xx_SBIMCONFIGLOW_REQUEST_TOUT_MASK; + bcm43xx_write32(bcm, BCM43xx_CIR_SBIMCONFIGLOW, value); + err = bcm43xx_pcicore_commit_settings(bcm); + assert(err == 0); + } + +out_switch_back: + err = bcm43xx_switch_core(bcm, old_core); +out: + return err; +} + +static void bcm43xx_softmac_init(struct bcm43xx_private *bcm) +{ + ieee80211softmac_start(bcm->net_dev); +} + +static void bcm43xx_periodic_work0_handler(void *d) +{ + struct bcm43xx_private *bcm = d; + unsigned long flags; + //TODO: unsigned int aci_average; + + spin_lock_irqsave(&bcm->lock, flags); + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + //FIXME: aci_average = bcm43xx_update_aci_average(bcm); + if (bcm->current_core->radio->aci_enable && bcm->current_core->radio->aci_wlan_automatic) { + bcm43xx_mac_suspend(bcm); + if (!bcm->current_core->radio->aci_enable && + 1 /*FIXME: We are not scanning? */) { + /*FIXME: First add bcm43xx_update_aci_average() before + * uncommenting this: */ + //if (bcm43xx_radio_aci_scan) + // bcm43xx_radio_set_interference_mitigation(bcm, + // BCM43xx_RADIO_INTERFMODE_MANUALWLAN); + } else if (1/*FIXME*/) { + //if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) + // bcm43xx_radio_set_interference_mitigation(bcm, + // BCM43xx_RADIO_INTERFMODE_MANUALWLAN); + } + bcm43xx_mac_enable(bcm); + } else if (bcm->current_core->radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN) { + if (bcm->current_core->phy->rev == 1) { + //FIXME: implement rev1 workaround + } + } + } + bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning? + //TODO for APHY (temperature?) + + if (likely(!bcm->shutting_down)) { + queue_delayed_work(bcm->workqueue, &bcm->periodic_work0, + BCM43xx_PERIODIC_0_DELAY); + } + spin_unlock_irqrestore(&bcm->lock, flags); +} + +static void bcm43xx_periodic_work1_handler(void *d) +{ + struct bcm43xx_private *bcm = d; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + + bcm43xx_phy_lo_mark_all_unused(bcm); + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + bcm43xx_mac_suspend(bcm); + bcm43xx_calc_nrssi_slope(bcm); + bcm43xx_mac_enable(bcm); + } + + if (likely(!bcm->shutting_down)) { + queue_delayed_work(bcm->workqueue, &bcm->periodic_work1, + BCM43xx_PERIODIC_1_DELAY); + } + spin_unlock_irqrestore(&bcm->lock, flags); +} + +static void bcm43xx_periodic_work2_handler(void *d) +{ + struct bcm43xx_private *bcm = d; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + + assert(bcm->current_core->phy->type == BCM43xx_PHYTYPE_G); + assert(bcm->current_core->phy->rev >= 2); + + bcm43xx_mac_suspend(bcm); + bcm43xx_phy_lo_g_measure(bcm); + bcm43xx_mac_enable(bcm); + + if (likely(!bcm->shutting_down)) { + queue_delayed_work(bcm->workqueue, &bcm->periodic_work2, + BCM43xx_PERIODIC_2_DELAY); + } + spin_unlock_irqrestore(&bcm->lock, flags); +} + +static void bcm43xx_periodic_work3_handler(void *d) +{ + struct bcm43xx_private *bcm = d; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + + /* Update device statistics. */ + bcm43xx_calculate_link_quality(bcm); + + if (likely(!bcm->shutting_down)) { + queue_delayed_work(bcm->workqueue, &bcm->periodic_work3, + BCM43xx_PERIODIC_3_DELAY); + } + spin_unlock_irqrestore(&bcm->lock, flags); +} + +/* Delete all periodic tasks and make + * sure they are not running any longer + */ +static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) +{ + cancel_delayed_work(&bcm->periodic_work0); + cancel_delayed_work(&bcm->periodic_work1); + cancel_delayed_work(&bcm->periodic_work2); + cancel_delayed_work(&bcm->periodic_work3); + flush_workqueue(bcm->workqueue); +} + +/* Setup all periodic tasks. */ +static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) +{ + INIT_WORK(&bcm->periodic_work0, bcm43xx_periodic_work0_handler, bcm); + INIT_WORK(&bcm->periodic_work1, bcm43xx_periodic_work1_handler, bcm); + INIT_WORK(&bcm->periodic_work2, bcm43xx_periodic_work2_handler, bcm); + INIT_WORK(&bcm->periodic_work3, bcm43xx_periodic_work3_handler, bcm); + + /* Periodic task 0: Delay ~15sec */ + queue_delayed_work(bcm->workqueue, &bcm->periodic_work0, + BCM43xx_PERIODIC_0_DELAY); + + /* Periodic task 1: Delay ~60sec */ + queue_delayed_work(bcm->workqueue, &bcm->periodic_work1, + BCM43xx_PERIODIC_1_DELAY); + + /* Periodic task 2: Delay ~120sec */ + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G && + bcm->current_core->phy->rev >= 2) { + queue_delayed_work(bcm->workqueue, &bcm->periodic_work2, + BCM43xx_PERIODIC_2_DELAY); + } + + /* Periodic task 3: Delay ~30sec */ + queue_delayed_work(bcm->workqueue, &bcm->periodic_work3, + BCM43xx_PERIODIC_3_DELAY); +} + +static void bcm43xx_security_init(struct bcm43xx_private *bcm) +{ + bcm->security_offset = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, + 0x0056) * 2; + bcm43xx_clear_keys(bcm); +} + +/* This is the opposite of bcm43xx_init_board() */ +static void bcm43xx_free_board(struct bcm43xx_private *bcm) +{ + int i, err; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + bcm->initialized = 0; + bcm->shutting_down = 1; + spin_unlock_irqrestore(&bcm->lock, flags); + + bcm43xx_periodic_tasks_delete(bcm); + + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE)) + continue; + if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED)) + continue; + + err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); + assert(err == 0); + bcm43xx_wireless_core_cleanup(bcm); + } + + bcm43xx_pctl_set_crystal(bcm, 0); + + spin_lock_irqsave(&bcm->lock, flags); + bcm->shutting_down = 0; + spin_unlock_irqrestore(&bcm->lock, flags); +} + +static int bcm43xx_init_board(struct bcm43xx_private *bcm) +{ + int i, err; + int num_80211_cores; + int connect_phy; + unsigned long flags; + + might_sleep(); + + spin_lock_irqsave(&bcm->lock, flags); + bcm->initialized = 0; + bcm->shutting_down = 0; + spin_unlock_irqrestore(&bcm->lock, flags); + + err = bcm43xx_pctl_set_crystal(bcm, 1); + if (err) + goto out; + err = bcm43xx_pctl_init(bcm); + if (err) + goto err_crystal_off; + err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_FAST); + if (err) + goto err_crystal_off; + + tasklet_enable(&bcm->isr_tasklet); + num_80211_cores = bcm43xx_num_80211_cores(bcm); + for (i = 0; i < num_80211_cores; i++) { + err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); + assert(err != -ENODEV); + if (err) + goto err_80211_unwind; + + /* Enable the selected wireless core. + * Connect PHY only on the first core. + */ + if (!bcm43xx_core_enabled(bcm)) { + if (num_80211_cores == 1) { + connect_phy = bcm->current_core->phy->connected; + } else { + if (i == 0) + connect_phy = 1; + else + connect_phy = 0; + } + bcm43xx_wireless_core_reset(bcm, connect_phy); + } + + if (i != 0) + bcm43xx_wireless_core_mark_inactive(bcm, &bcm->core_80211[0]); + + err = bcm43xx_wireless_core_init(bcm); + if (err) + goto err_80211_unwind; + + if (i != 0) { + bcm43xx_mac_suspend(bcm); + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + bcm43xx_radio_turn_off(bcm); + } + } + bcm->active_80211_core = &bcm->core_80211[0]; + if (num_80211_cores >= 2) { + bcm43xx_switch_core(bcm, &bcm->core_80211[0]); + bcm43xx_mac_enable(bcm); + } + bcm43xx_macfilter_clear(bcm, BCM43xx_MACFILTER_ASSOC); + bcm43xx_macfilter_set(bcm, BCM43xx_MACFILTER_SELF, (u8 *)(bcm->net_dev->dev_addr)); + dprintk(KERN_INFO PFX "80211 cores initialized\n"); + bcm43xx_security_init(bcm); + bcm43xx_softmac_init(bcm); + + bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); + + spin_lock_irqsave(&bcm->lock, flags); + bcm->initialized = 1; + spin_unlock_irqrestore(&bcm->lock, flags); + + if (bcm->current_core->radio->initial_channel != 0xFF) { + bcm43xx_mac_suspend(bcm); + bcm43xx_radio_selectchannel(bcm, bcm->current_core->radio->initial_channel, 0); + bcm43xx_mac_enable(bcm); + } + bcm43xx_periodic_tasks_setup(bcm); + + assert(err == 0); +out: + return err; + +err_80211_unwind: + tasklet_disable(&bcm->isr_tasklet); + /* unwind all 80211 initialization */ + for (i = 0; i < num_80211_cores; i++) { + if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED)) + continue; + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + bcm43xx_wireless_core_cleanup(bcm); + } +err_crystal_off: + bcm43xx_pctl_set_crystal(bcm, 0); + goto out; +} + +static void bcm43xx_detach_board(struct bcm43xx_private *bcm) +{ + struct pci_dev *pci_dev = bcm->pci_dev; + int i; + + bcm43xx_chipset_detach(bcm); + /* Do _not_ access the chip, after it is detached. */ + iounmap(bcm->mmio_addr); + + pci_release_regions(pci_dev); + pci_disable_device(pci_dev); + + /* Free allocated structures/fields */ + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + kfree(bcm->phy[i]._lo_pairs); + if (bcm->phy[i].dyn_tssi_tbl) + kfree(bcm->phy[i].tssi2dbm); + } +} + +static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) +{ + u16 value; + u8 phy_version; + u8 phy_type; + u8 phy_rev; + int phy_rev_ok = 1; + void *p; + + value = bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); + + phy_version = (value & 0xF000) >> 12; + phy_type = (value & 0x0F00) >> 8; + phy_rev = (value & 0x000F); + + dprintk(KERN_INFO PFX "Detected PHY: Version: %x, Type %x, Revision %x\n", + phy_version, phy_type, phy_rev); + + switch (phy_type) { + case BCM43xx_PHYTYPE_A: + if (phy_rev >= 4) + phy_rev_ok = 0; + /*FIXME: We need to switch the ieee->modulation, etc.. flags, + * if we switch 80211 cores after init is done. + * As we do not implement on the fly switching between + * wireless cores, I will leave this as a future task. + */ + bcm->ieee->modulation = IEEE80211_OFDM_MODULATION; + bcm->ieee->mode = IEEE_A; + bcm->ieee->freq_band = IEEE80211_52GHZ_BAND | + IEEE80211_24GHZ_BAND; + break; + case BCM43xx_PHYTYPE_B: + if (phy_rev != 2 && phy_rev != 4 && phy_rev != 6 && phy_rev != 7) + phy_rev_ok = 0; + bcm->ieee->modulation = IEEE80211_CCK_MODULATION; + bcm->ieee->mode = IEEE_B; + bcm->ieee->freq_band = IEEE80211_24GHZ_BAND; + break; + case BCM43xx_PHYTYPE_G: + if (phy_rev > 7) + phy_rev_ok = 0; + bcm->ieee->modulation = IEEE80211_OFDM_MODULATION | + IEEE80211_CCK_MODULATION; + bcm->ieee->mode = IEEE_G; + bcm->ieee->freq_band = IEEE80211_24GHZ_BAND; + break; + default: + printk(KERN_ERR PFX "Error: Unknown PHY Type %x\n", + phy_type); + return -ENODEV; + }; + if (!phy_rev_ok) { + printk(KERN_WARNING PFX "Invalid PHY Revision %x\n", + phy_rev); + } + + bcm->current_core->phy->version = phy_version; + bcm->current_core->phy->type = phy_type; + bcm->current_core->phy->rev = phy_rev; + if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) { + p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT, + GFP_KERNEL); + if (!p) + return -ENOMEM; + bcm->current_core->phy->_lo_pairs = p; + } + + return 0; +} + +static int bcm43xx_attach_board(struct bcm43xx_private *bcm) +{ + struct pci_dev *pci_dev = bcm->pci_dev; + struct net_device *net_dev = bcm->net_dev; + int err; + int i; + void __iomem *ioaddr; + unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; + int num_80211_cores; + u32 coremask; + + err = pci_enable_device(pci_dev); + if (err) { + printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err); + err = -ENODEV; + goto out; + } + + mmio_start = pci_resource_start(pci_dev, 0); + mmio_end = pci_resource_end(pci_dev, 0); + mmio_flags = pci_resource_flags(pci_dev, 0); + mmio_len = pci_resource_len(pci_dev, 0); + + /* make sure PCI base addr is MMIO */ + if (!(mmio_flags & IORESOURCE_MEM)) { + printk(KERN_ERR PFX + "%s, region #0 not an MMIO resource, aborting\n", + pci_name(pci_dev)); + err = -ENODEV; + goto err_pci_disable; + } +//FIXME: Why is this check disabled for BCM947XX? What is the IO_SIZE there? +#ifndef CONFIG_BCM947XX + if (mmio_len != BCM43xx_IO_SIZE) { + printk(KERN_ERR PFX + "%s: invalid PCI mem region size(s), aborting\n", + pci_name(pci_dev)); + err = -ENODEV; + goto err_pci_disable; + } +#endif + + err = pci_request_regions(pci_dev, DRV_NAME); + if (err) { + printk(KERN_ERR PFX + "could not access PCI resources (%i)\n", err); + goto err_pci_disable; + } + + /* enable PCI bus-mastering */ + pci_set_master(pci_dev); + + /* ioremap MMIO region */ + ioaddr = ioremap(mmio_start, mmio_len); + if (!ioaddr) { + printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", + pci_name(pci_dev)); + err = -EIO; + goto err_pci_release; + } + + net_dev->base_addr = (unsigned long)ioaddr; + bcm->mmio_addr = ioaddr; + bcm->mmio_len = mmio_len; + + bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, + &bcm->board_vendor); + bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_ID, + &bcm->board_type); + bcm43xx_pci_read_config16(bcm, PCI_REVISION_ID, + &bcm->board_revision); + + err = bcm43xx_chipset_attach(bcm); + if (err) + goto err_iounmap; + err = bcm43xx_pctl_init(bcm); + if (err) + goto err_chipset_detach; + err = bcm43xx_probe_cores(bcm); + if (err) + goto err_chipset_detach; + + num_80211_cores = bcm43xx_num_80211_cores(bcm); + + /* Attach all IO cores to the backplane. */ + coremask = 0; + for (i = 0; i < num_80211_cores; i++) + coremask |= (1 << bcm->core_80211[i].index); + //FIXME: Also attach some non80211 cores? + err = bcm43xx_setup_backplane_pci_connection(bcm, coremask); + if (err) { + printk(KERN_ERR PFX "Backplane->PCI connection failed!\n"); + goto err_chipset_detach; + } + + err = bcm43xx_read_sprom(bcm); + if (err) + goto err_chipset_detach; + err = bcm43xx_leds_init(bcm); + if (err) + goto err_chipset_detach; + + for (i = 0; i < num_80211_cores; i++) { + err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); + assert(err != -ENODEV); + if (err) + goto err_80211_unwind; + + /* Enable the selected wireless core. + * Connect PHY only on the first core. + */ + bcm43xx_wireless_core_reset(bcm, (i == 0)); + + err = bcm43xx_read_phyinfo(bcm); + if (err && (i == 0)) + goto err_80211_unwind; + + err = bcm43xx_read_radioinfo(bcm); + if (err && (i == 0)) + goto err_80211_unwind; + + err = bcm43xx_validate_chip(bcm); + if (err && (i == 0)) + goto err_80211_unwind; + + bcm43xx_radio_turn_off(bcm); + err = bcm43xx_phy_init_tssi2dbm_table(bcm); + if (err) + goto err_80211_unwind; + bcm43xx_wireless_core_disable(bcm); + } + bcm43xx_pctl_set_crystal(bcm, 0); + + /* Set the MAC address in the networking subsystem */ + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6); + else + memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6); + + bcm43xx_geo_init(bcm); + + snprintf(bcm->nick, IW_ESSID_MAX_SIZE, + "Broadcom %04X", bcm->chip_id); + + assert(err == 0); +out: + return err; + +err_80211_unwind: + for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { + kfree(bcm->phy[i]._lo_pairs); + if (bcm->phy[i].dyn_tssi_tbl) + kfree(bcm->phy[i].tssi2dbm); + } +err_chipset_detach: + bcm43xx_chipset_detach(bcm); +err_iounmap: + iounmap(bcm->mmio_addr); +err_pci_release: + pci_release_regions(pci_dev); +err_pci_disable: + pci_disable_device(pci_dev); + goto out; +} + +static inline +s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, u8 in_rssi, + int ofdm, int adjust_2053, int adjust_2050) +{ + s32 tmp; + + switch (bcm->current_core->radio->version) { + case 0x2050: + if (ofdm) { + tmp = in_rssi; + if (tmp > 127) + tmp -= 256; + tmp *= 73; + tmp /= 64; + if (adjust_2050) + tmp += 25; + else + tmp -= 3; + } else { + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + if (in_rssi > 63) + in_rssi = 63; + tmp = bcm->current_core->radio->nrssi_lt[in_rssi]; + tmp = 31 - tmp; + tmp *= -131; + tmp /= 128; + tmp -= 57; + } else { + tmp = in_rssi; + tmp = 31 - tmp; + tmp *= -149; + tmp /= 128; + tmp -= 68; + } + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G && + adjust_2050) + tmp += 25; + } + break; + case 0x2060: + if (in_rssi > 127) + tmp = in_rssi - 256; + else + tmp = in_rssi; + break; + default: + tmp = in_rssi; + tmp -= 11; + tmp *= 103; + tmp /= 64; + if (adjust_2053) + tmp -= 109; + else + tmp -= 83; + } + + return (s8)tmp; +} + +static inline +s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, u8 in_rssi) +{ + s8 ret; + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { + //TODO: Incomplete specs. + ret = 0; + } else + ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1); + + return ret; +} + +static inline +int bcm43xx_rx_packet(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct ieee80211_rx_stats *stats) +{ + int err; + + err = ieee80211_rx(bcm->ieee, skb, stats); + if (unlikely(err == 0)) + return -EINVAL; + return 0; +} + +int fastcall bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr) +{ + struct bcm43xx_plcp_hdr4 *plcp; + struct ieee80211_rx_stats stats; + struct ieee80211_hdr_4addr *wlhdr; + u16 frame_ctl; + int is_packet_for_us = 0; + int err = -EINVAL; + const u16 rxflags1 = le16_to_cpu(rxhdr->flags1); + const u16 rxflags2 = le16_to_cpu(rxhdr->flags2); + const u16 rxflags3 = le16_to_cpu(rxhdr->flags3); + const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM); + + if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) { + plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2); + /* Skip two unknown bytes and the PLCP header. */ + skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6)); + } else { + plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data); + /* Skip the PLCP header. */ + skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6)); + } + /* The SKB contains the PAYLOAD (wireless header + data) + * at this point. The FCS at the end is stripped. + */ + + memset(&stats, 0, sizeof(stats)); + stats.mac_time = le16_to_cpu(rxhdr->mactime); + stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, + !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), + !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); + stats.signal = rxhdr->signal_quality; //FIXME +//TODO stats.noise = + stats.rate = bcm43xx_plcp_get_bitrate(plcp, is_ofdm); +//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); + stats.received_channel = bcm->current_core->radio->channel; +//TODO stats.control = + stats.mask = IEEE80211_STATMASK_SIGNAL | +//TODO IEEE80211_STATMASK_NOISE | + IEEE80211_STATMASK_RATE | + IEEE80211_STATMASK_RSSI; + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + stats.freq = IEEE80211_52GHZ_BAND; + else + stats.freq = IEEE80211_24GHZ_BAND; + stats.len = skb->len; + + bcm->stats.last_rx = jiffies; + if (bcm->ieee->iw_mode == IW_MODE_MONITOR) + return bcm43xx_rx_packet(bcm, skb, &stats); + + wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); + + switch (bcm->ieee->iw_mode) { + case IW_MODE_ADHOC: + if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || + memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || + is_broadcast_ether_addr(wlhdr->addr1) || + is_multicast_ether_addr(wlhdr->addr1) || + bcm->net_dev->flags & IFF_PROMISC) + is_packet_for_us = 1; + break; + case IW_MODE_INFRA: + default: + /* When receiving multicast or broadcast packets, filter out + the packets we send ourself; we shouldn't see those */ + if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || + memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || + (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) && + (is_broadcast_ether_addr(wlhdr->addr1) || + is_multicast_ether_addr(wlhdr->addr1) || + bcm->net_dev->flags & IFF_PROMISC))) + is_packet_for_us = 1; + break; + } + + frame_ctl = le16_to_cpu(wlhdr->frame_ctl); + + if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) { + frame_ctl &= ~IEEE80211_FCTL_PROTECTED; + wlhdr->frame_ctl = cpu_to_le16(frame_ctl); + /* trim IV and ICV */ + /* FIXME: this must be done only for WEP encrypted packets */ + if (skb->len < 32) { + dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag " + "set and length < 32)\n"); + return -EINVAL; + } else { + memmove(skb->data + 4, skb->data, 24); + skb_pull(skb, 4); + skb_trim(skb, skb->len - 4); + stats.len -= 8; + } + /* do _not_ use wlhdr again without reassigning it */ + } + + switch (WLAN_FC_GET_TYPE(frame_ctl)) { + case IEEE80211_FTYPE_MGMT: + ieee80211_rx_mgt(bcm->ieee, skb->data, &stats); + break; + case IEEE80211_FTYPE_DATA: + if (is_packet_for_us) + err = bcm43xx_rx_packet(bcm, skb, &stats); + break; + case IEEE80211_FTYPE_CTL: + break; + default: + assert(0); + return -EINVAL; + } + + return err; +} + +/* Do the Hardware IO operations to send the txb */ +static inline int bcm43xx_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + int err = -ENODEV; + + if (bcm->pio_mode) + err = bcm43xx_pio_transfer_txb(bcm, txb); + else + err = bcm43xx_dma_transfer_txb(bcm, txb); + + return err; +} + +static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, + u8 channel) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_mac_suspend(bcm); + bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_mac_enable(bcm); + spin_unlock_irqrestore(&bcm->lock, flags); +} + +/* set_security() callback in struct ieee80211_device */ +static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, + struct ieee80211_security *sec) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct ieee80211_security *secinfo = &bcm->ieee->sec; + unsigned long flags; + int keyidx; + + dprintk(KERN_INFO PFX "set security called\n"); + + spin_lock_irqsave(&bcm->lock, flags); + + for (keyidx = 0; keyidxflags & (1<encode_alg[keyidx] = sec->encode_alg[keyidx]; + secinfo->key_sizes[keyidx] = sec->key_sizes[keyidx]; + memcpy(secinfo->keys[keyidx], sec->keys[keyidx], SCM_KEY_LEN); + } + + if (sec->flags & SEC_ACTIVE_KEY) { + secinfo->active_key = sec->active_key; + dprintk(KERN_INFO PFX " .active_key = %d\n", sec->active_key); + } + if (sec->flags & SEC_UNICAST_GROUP) { + secinfo->unicast_uses_group = sec->unicast_uses_group; + dprintk(KERN_INFO PFX " .unicast_uses_group = %d\n", sec->unicast_uses_group); + } + if (sec->flags & SEC_LEVEL) { + secinfo->level = sec->level; + dprintk(KERN_INFO PFX " .level = %d\n", sec->level); + } + if (sec->flags & SEC_ENABLED) { + secinfo->enabled = sec->enabled; + dprintk(KERN_INFO PFX " .enabled = %d\n", sec->enabled); + } + if (sec->flags & SEC_ENCRYPT) { + secinfo->encrypt = sec->encrypt; + dprintk(KERN_INFO PFX " .encrypt = %d\n", sec->encrypt); + } + if (bcm->initialized && !bcm->ieee->host_encrypt) { + if (secinfo->enabled) { + /* upload WEP keys to hardware */ + char null_address[6] = { 0 }; + u8 algorithm = 0; + for (keyidx = 0; keyidxflags & (1<encode_alg[keyidx]) { + case SEC_ALG_NONE: algorithm = BCM43xx_SEC_ALGO_NONE; break; + case SEC_ALG_WEP: + algorithm = BCM43xx_SEC_ALGO_WEP; + if (secinfo->key_sizes[keyidx] == 13) + algorithm = BCM43xx_SEC_ALGO_WEP104; + break; + case SEC_ALG_TKIP: + FIXME(); + algorithm = BCM43xx_SEC_ALGO_TKIP; + break; + case SEC_ALG_CCMP: + FIXME(); + algorithm = BCM43xx_SEC_ALGO_AES; + break; + default: + assert(0); + break; + } + bcm43xx_key_write(bcm, keyidx, algorithm, sec->keys[keyidx], secinfo->key_sizes[keyidx], &null_address[0]); + bcm->key[keyidx].enabled = 1; + bcm->key[keyidx].algorithm = algorithm; + } + } else + bcm43xx_clear_keys(bcm); + } + spin_unlock_irqrestore(&bcm->lock, flags); +} + +/* hard_start_xmit() callback in struct ieee80211_device */ +static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb, + struct net_device *net_dev, + int pri) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err = -ENODEV; + unsigned long flags; + + spin_lock_irqsave(&bcm->lock, flags); + if (likely(bcm->initialized)) + err = bcm43xx_tx(bcm, txb); + spin_unlock_irqrestore(&bcm->lock, flags); + + return err; +} + +static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_dev) +{ + return &(bcm43xx_priv(net_dev)->ieee->stats); +} + +static void bcm43xx_net_tx_timeout(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + + bcm43xx_controller_restart(bcm, "TX timeout"); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void bcm43xx_net_poll_controller(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + local_irq_save(flags); + bcm43xx_interrupt_handler(bcm->irq, bcm, NULL); + local_irq_restore(flags); +} +#endif /* CONFIG_NET_POLL_CONTROLLER */ + +static int bcm43xx_net_open(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + + return bcm43xx_init_board(bcm); +} + +static int bcm43xx_net_stop(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + + ieee80211softmac_stop(net_dev); + bcm43xx_disable_interrupts_sync(bcm, NULL); + bcm43xx_free_board(bcm); + + return 0; +} + +static void bcm43xx_init_private(struct bcm43xx_private *bcm, + struct net_device *net_dev, + struct pci_dev *pci_dev, + struct workqueue_struct *wq) +{ + bcm->ieee = netdev_priv(net_dev); + bcm->softmac = ieee80211_priv(net_dev); + bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; + bcm->workqueue = wq; + +#ifdef DEBUG_ENABLE_MMIO_PRINT + bcm43xx_mmioprint_initial(bcm, 1); +#else + bcm43xx_mmioprint_initial(bcm, 0); +#endif +#ifdef DEBUG_ENABLE_PCILOG + bcm43xx_pciprint_initial(bcm, 1); +#else + bcm43xx_pciprint_initial(bcm, 0); +#endif + + bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; + bcm->pci_dev = pci_dev; + bcm->net_dev = net_dev; + if (modparam_bad_frames_preempt) + bcm->bad_frames_preempt = 1; + spin_lock_init(&bcm->lock); + tasklet_init(&bcm->isr_tasklet, + (void (*)(unsigned long))bcm43xx_interrupt_tasklet, + (unsigned long)bcm); + tasklet_disable_nosync(&bcm->isr_tasklet); + if (modparam_pio) { + bcm->pio_mode = 1; + } else { + if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK) == 0) { + bcm->pio_mode = 0; + } else { + printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n"); + bcm->pio_mode = 1; + } + } + bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD; + + /* default to sw encryption for now */ + bcm->ieee->host_build_iv = 0; + bcm->ieee->host_encrypt = 1; + bcm->ieee->host_decrypt = 1; + + bcm->ieee->iw_mode = BCM43xx_INITIAL_IWMODE; + bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr); + bcm->ieee->set_security = bcm43xx_ieee80211_set_security; + bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit; +} + +static int __devinit bcm43xx_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *net_dev; + struct bcm43xx_private *bcm; + struct workqueue_struct *wq; + int err; + +#ifdef CONFIG_BCM947XX + if ((pdev->bus->number == 0) && (pdev->device != 0x0800)) + return -ENODEV; +#endif + +#ifdef DEBUG_SINGLE_DEVICE_ONLY + if (strcmp(pci_name(pdev), DEBUG_SINGLE_DEVICE_ONLY)) + return -ENODEV; +#endif + + net_dev = alloc_ieee80211softmac(sizeof(*bcm)); + if (!net_dev) { + printk(KERN_ERR PFX + "could not allocate ieee80211 device %s\n", + pci_name(pdev)); + err = -ENOMEM; + goto out; + } + /* initialize the net_device struct */ + SET_MODULE_OWNER(net_dev); + SET_NETDEV_DEV(net_dev, &pdev->dev); + + net_dev->open = bcm43xx_net_open; + net_dev->stop = bcm43xx_net_stop; + net_dev->get_stats = bcm43xx_net_get_stats; + net_dev->tx_timeout = bcm43xx_net_tx_timeout; +#ifdef CONFIG_NET_POLL_CONTROLLER + net_dev->poll_controller = bcm43xx_net_poll_controller; +#endif + net_dev->wireless_handlers = &bcm43xx_wx_handlers_def; + net_dev->irq = pdev->irq; + net_dev->watchdog_timeo = BCM43xx_TX_TIMEOUT; + + /* initialize the bcm43xx_private struct */ + bcm = bcm43xx_priv(net_dev); + memset(bcm, 0, sizeof(*bcm)); + wq = create_workqueue(DRV_NAME "_wq"); + if (!wq) { + err = -ENOMEM; + goto err_free_netdev; + } + bcm43xx_init_private(bcm, net_dev, pdev, wq); + + pci_set_drvdata(pdev, net_dev); + + err = bcm43xx_attach_board(bcm); + if (err) + goto err_destroy_wq; + + err = register_netdev(net_dev); + if (err) { + printk(KERN_ERR PFX "Cannot register net device, " + "aborting.\n"); + err = -ENOMEM; + goto err_detach_board; + } + + bcm43xx_debugfs_add_device(bcm); + + assert(err == 0); +out: + return err; + +err_detach_board: + bcm43xx_detach_board(bcm); +err_destroy_wq: + destroy_workqueue(wq); +err_free_netdev: + free_ieee80211softmac(net_dev); + goto out; +} + +static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) +{ + struct net_device *net_dev = pci_get_drvdata(pdev); + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + + bcm43xx_debugfs_remove_device(bcm); + unregister_netdev(net_dev); + bcm43xx_detach_board(bcm); + assert(bcm->ucode == NULL); + destroy_workqueue(bcm->workqueue); + free_ieee80211softmac(net_dev); +} + +/* Hard-reset the chip. Do not call this directly. + * Use bcm43xx_controller_restart() + */ +static void bcm43xx_chip_reset(void *_bcm) +{ + struct bcm43xx_private *bcm = _bcm; + struct net_device *net_dev = bcm->net_dev; + struct pci_dev *pci_dev = bcm->pci_dev; + struct workqueue_struct *wq = bcm->workqueue; + int err; + int was_initialized = bcm->initialized; + + netif_stop_queue(bcm->net_dev); + tasklet_disable(&bcm->isr_tasklet); + + bcm->firmware_norelease = 1; + if (was_initialized) + bcm43xx_free_board(bcm); + bcm->firmware_norelease = 0; + bcm43xx_detach_board(bcm); + bcm43xx_init_private(bcm, net_dev, pci_dev, wq); + err = bcm43xx_attach_board(bcm); + if (err) + goto failure; + if (was_initialized) { + err = bcm43xx_init_board(bcm); + if (err) + goto failure; + } + netif_wake_queue(bcm->net_dev); + printk(KERN_INFO PFX "Controller restarted\n"); + + return; +failure: + printk(KERN_ERR PFX "Controller restart failed\n"); +} + +/* Hard-reset the chip. + * This can be called from interrupt or process context. + * Make sure to _not_ re-enable device interrupts after this has been called. +*/ +void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) +{ + bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); + INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); + queue_work(bcm->workqueue, &bcm->restart_work); +} + +#ifdef CONFIG_PM + +static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *net_dev = pci_get_drvdata(pdev); + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int try_to_shutdown = 0, err; + + dprintk(KERN_INFO PFX "Suspending...\n"); + + spin_lock_irqsave(&bcm->lock, flags); + bcm->was_initialized = bcm->initialized; + if (bcm->initialized) + try_to_shutdown = 1; + spin_unlock_irqrestore(&bcm->lock, flags); + + netif_device_detach(net_dev); + if (try_to_shutdown) { + ieee80211softmac_stop(net_dev); + err = bcm43xx_disable_interrupts_sync(bcm, &bcm->irq_savedstate); + if (unlikely(err)) { + dprintk(KERN_ERR PFX "Suspend failed.\n"); + return -EAGAIN; + } + bcm->firmware_norelease = 1; + bcm43xx_free_board(bcm); + bcm->firmware_norelease = 0; + } + bcm43xx_chipset_detach(bcm); + + pci_save_state(pdev); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + dprintk(KERN_INFO PFX "Device suspended.\n"); + + return 0; +} + +static int bcm43xx_resume(struct pci_dev *pdev) +{ + struct net_device *net_dev = pci_get_drvdata(pdev); + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err = 0; + + dprintk(KERN_INFO PFX "Resuming...\n"); + + pci_set_power_state(pdev, 0); + pci_enable_device(pdev); + pci_restore_state(pdev); + + bcm43xx_chipset_attach(bcm); + if (bcm->was_initialized) { + bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; + err = bcm43xx_init_board(bcm); + } + if (err) { + printk(KERN_ERR PFX "Resume failed!\n"); + return err; + } + + netif_device_attach(net_dev); + + /*FIXME: This should be handled by softmac instead. */ + schedule_work(&bcm->softmac->associnfo.work); + + dprintk(KERN_INFO PFX "Device resumed.\n"); + + return 0; +} + +#endif /* CONFIG_PM */ + +static struct pci_driver bcm43xx_pci_driver = { + .name = BCM43xx_DRIVER_NAME, + .id_table = bcm43xx_pci_tbl, + .probe = bcm43xx_init_one, + .remove = __devexit_p(bcm43xx_remove_one), +#ifdef CONFIG_PM + .suspend = bcm43xx_suspend, + .resume = bcm43xx_resume, +#endif /* CONFIG_PM */ +}; + +static int __init bcm43xx_init(void) +{ + printk(KERN_INFO BCM43xx_DRIVER_NAME "\n"); + bcm43xx_debugfs_init(); + return pci_register_driver(&bcm43xx_pci_driver); +} + +static void __exit bcm43xx_exit(void) +{ + pci_unregister_driver(&bcm43xx_pci_driver); + bcm43xx_debugfs_exit(); +} + +module_init(bcm43xx_init) +module_exit(bcm43xx_exit) + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h new file mode 100644 index 00000000000..1d3eddd314b --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -0,0 +1,283 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_MAIN_H_ +#define BCM43xx_MAIN_H_ + +#include "bcm43xx.h" + +#ifdef CONFIG_BCM947XX +#define atoi(str) simple_strtoul(((str != NULL) ? str : ""), NULL, 0) + +static inline void e_aton(char *str, char *dest) +{ + int i = 0; + u16 *d = (u16 *) dest; + + for (;;) { + dest[i++] = (char) simple_strtoul(str, NULL, 16); + str += 2; + if (!*str++ || i == 6) + break; + } + for (i = 0; i < 3; i++) + d[i] = cpu_to_be16(d[i]); +} +#endif + + +#define _bcm43xx_declare_plcp_hdr(size) \ + struct bcm43xx_plcp_hdr##size { \ + union { \ + __le32 data; \ + __u8 raw[size]; \ + } __attribute__((__packed__)); \ + } __attribute__((__packed__)) + +/* struct bcm43xx_plcp_hdr4 */ +_bcm43xx_declare_plcp_hdr(4); +/* struct bcm430c_plcp_hdr6 */ +_bcm43xx_declare_plcp_hdr(6); + +#undef _bcm43xx_declare_plcp_hdr + + +#define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes] +#define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes) +/* Magic helper macro to pad structures. Ignore those above. It's magic. */ +#define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) + + +/* Device specific TX header. To be prepended to TX frames. */ +struct bcm43xx_txhdr { + union { + struct { + u16 flags; + u16 wsec_rate; + u16 frame_control; + u16 unknown_zeroed_0; + u16 control; + unsigned char wep_iv[10]; + unsigned char unknown_wsec_tkip_data[3]; //FIXME + PAD_BYTES(3); + unsigned char mac1[6]; + u16 unknown_zeroed_1; + struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp; + u16 rts_cts_dur_fallback; + struct bcm43xx_plcp_hdr4 fallback_plcp; + u16 fallback_dur_id; + PAD_BYTES(2); + u16 cookie; + u16 unknown_scb_stuff; //FIXME + struct bcm43xx_plcp_hdr6 rts_cts_plcp; + u16 rts_cts_frame_type; + u16 rts_cts_dur; + unsigned char rts_cts_mac1[6]; + unsigned char rts_cts_mac2[6]; + PAD_BYTES(2); + struct bcm43xx_plcp_hdr6 plcp; + } __attribute__((__packed__)); + + unsigned char raw[82]; + } __attribute__((__packed__)); +} __attribute__((__packed__)); + +struct sk_buff; + +void FASTCALL(bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + const unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie)); + +/* RX header as received from the hardware. */ +struct bcm43xx_rxhdr { + /* Frame Length. Must be generated explicitely in PIO mode. */ + __le16 frame_length; + PAD_BYTES(2); + /* Flags field 1 */ + __le16 flags1; + u8 rssi; + u8 signal_quality; + PAD_BYTES(2); + /* Flags field 3 */ + __le16 flags3; + /* Flags field 2 */ + __le16 flags2; + /* Lower 16bits of the TSF at the time the frame started. */ + __le16 mactime; + PAD_BYTES(14); +} __attribute__((__packed__)); + +#define BCM43xx_RXHDR_FLAGS1_OFDM (1 << 0) +/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL??? (1 << 3) FIXME */ +#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE (1 << 7) +#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ (1 << 14) + +#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME (1 << 0) +#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME (1 << 2) +/*FIXME: WEP related flags */ + +#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ (1 << 10) + +/* Transmit Status as received from the hardware. */ +struct bcm43xx_hwxmitstatus { + PAD_BYTES(4); + __le16 cookie; + u8 flags; + u8 cnt1:4, + cnt2:4; + PAD_BYTES(2); + __le16 seq; + __le16 unknown; //FIXME +} __attribute__((__packed__)); + +/* Transmit Status in CPU byteorder. */ +struct bcm43xx_xmitstatus { + u16 cookie; + u8 flags; + u8 cnt1:4, + cnt2:4; + u16 seq; + u16 unknown; //FIXME +}; + +#define BCM43xx_TXSTAT_FLAG_ACK 0x01 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10 +#define BCM43xx_TXSTAT_FLAG_IGNORE 0x20 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80 + +struct bcm43xx_xmitstatus_queue { + struct list_head list; + struct bcm43xx_hwxmitstatus status; +}; + + +/* Lightweight function to convert a frequency (in Mhz) to a channel number. */ +static inline +u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm, + int freq) +{ + u8 channel; + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { + channel = (freq - 5000) / 5; + } else { + if (freq == 2484) + channel = 14; + else + channel = (freq - 2407) / 5; + } + + return channel; +} + +/* Lightweight function to convert a channel number to a frequency (in Mhz). */ +static inline +int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm, + u8 channel) +{ + int freq; + + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { + freq = 5000 + (5 * channel); + } else { + if (channel == 14) + freq = 2484; + else + freq = 2407 + (5 * channel); + } + + return freq; +} + +/* Lightweight function to check if a channel number is valid. + * Note that this does _NOT_ check for geographical restrictions! + */ +static inline +int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, + u8 channel) +{ + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { + if (channel <= 200) + return 1; + } else { + if (channel >= 1 && channel <= 14) + return 1; + } + + return 0; +} + +void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf); +void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf); + +int FASTCALL(bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr)); + +void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, + int iw_mode); + +u32 bcm43xx_shm_read32(struct bcm43xx_private *bcm, + u16 routing, u16 offset); +u16 bcm43xx_shm_read16(struct bcm43xx_private *bcm, + u16 routing, u16 offset); +void bcm43xx_shm_write32(struct bcm43xx_private *bcm, + u16 routing, u16 offset, + u32 value); +void bcm43xx_shm_write16(struct bcm43xx_private *bcm, + u16 routing, u16 offset, + u16 value); + +void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm); + +int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core); + +void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); + +int bcm43xx_pci_read_config_16(struct pci_dev *pdev, u16 offset, u16 *val); +int bcm43xx_pci_read_config_32(struct pci_dev *pdev, u16 offset, u32 *val); +int bcm43xx_pci_write_config_16(struct pci_dev *pdev, int offset, u16 val); +int bcm43xx_pci_write_config_32(struct pci_dev *pdev, int offset, u32 val); + +void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); +void bcm43xx_mac_enable(struct bcm43xx_private *bcm); + +u8 bcm43xx_sprom_crc(const u16 *sprom); + +void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); + +#endif /* BCM43xx_MAIN_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c new file mode 100644 index 00000000000..41b9cd7fc9e --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -0,0 +1,2122 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include + +#include "bcm43xx.h" +#include "bcm43xx_phy.h" +#include "bcm43xx_main.h" +#include "bcm43xx_radio.h" +#include "bcm43xx_ilt.h" +#include "bcm43xx_power.h" + + +static const s8 bcm43xx_tssi2dbm_b_table[] = { + 0x4D, 0x4C, 0x4B, 0x4A, + 0x4A, 0x49, 0x48, 0x47, + 0x47, 0x46, 0x45, 0x45, + 0x44, 0x43, 0x42, 0x42, + 0x41, 0x40, 0x3F, 0x3E, + 0x3D, 0x3C, 0x3B, 0x3A, + 0x39, 0x38, 0x37, 0x36, + 0x35, 0x34, 0x32, 0x31, + 0x30, 0x2F, 0x2D, 0x2C, + 0x2B, 0x29, 0x28, 0x26, + 0x25, 0x23, 0x21, 0x1F, + 0x1D, 0x1A, 0x17, 0x14, + 0x10, 0x0C, 0x06, 0x00, + -7, -7, -7, -7, + -7, -7, -7, -7, + -7, -7, -7, -7, +}; + +static const s8 bcm43xx_tssi2dbm_g_table[] = { + 77, 77, 77, 76, + 76, 76, 75, 75, + 74, 74, 73, 73, + 73, 72, 72, 71, + 71, 70, 70, 69, + 68, 68, 67, 67, + 66, 65, 65, 64, + 63, 63, 62, 61, + 60, 59, 58, 57, + 56, 55, 54, 53, + 52, 50, 49, 47, + 45, 43, 40, 37, + 33, 28, 22, 14, + 5, -7, -20, -20, + -20, -20, -20, -20, + -20, -20, -20, -20, +}; + +static void bcm43xx_phy_initg(struct bcm43xx_private *bcm); + + +void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + + assert(irqs_disabled()); + if (bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) == 0x00000000) { + phy->is_locked = 0; + return; + } + if (bcm->current_core->rev < 3) { + bcm43xx_mac_suspend(bcm); + spin_lock(&phy->lock); + } else { + if (bcm->ieee->iw_mode != IW_MODE_MASTER) + bcm43xx_power_saving_ctl_bits(bcm, -1, 1); + } + phy->is_locked = 1; +} + +void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + + assert(irqs_disabled()); + if (bcm->current_core->rev < 3) { + if (phy->is_locked) { + spin_unlock(&phy->lock); + bcm43xx_mac_enable(bcm); + } + } else { + if (bcm->ieee->iw_mode != IW_MODE_MASTER) + bcm43xx_power_saving_ctl_bits(bcm, -1, -1); + } + phy->is_locked = 0; +} + +u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset) +{ + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset); + return bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_DATA); +} + +void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val) +{ + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset); + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_DATA, val); +} + +void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + unsigned long flags; + + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */ + if (phy->calibrated) + return; + if (phy->type == BCM43xx_PHYTYPE_G && phy->rev == 1) { + /* We do not want to be preempted while calibrating + * the hardware. + */ + local_irq_save(flags); + + bcm43xx_wireless_core_reset(bcm, 0); + bcm43xx_phy_initg(bcm); + bcm43xx_wireless_core_reset(bcm, 1); + + local_irq_restore(flags); + } + phy->calibrated = 1; +} + +/* Connect the PHY + * http://bcm-specs.sipsolutions.net/SetPHY + */ +int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect) +{ + u32 flags; + + if (bcm->current_core->rev < 5) { + if (connect) { + bcm->current_core->phy->connected = 1; + dprintk(KERN_INFO PFX "PHY connected\n"); + } else { + bcm->current_core->phy->connected = 0; + dprintk(KERN_INFO PFX "PHY disconnected\n"); + } + return 0; + } + + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); + if (connect) { + if (!(flags & 0x00010000)) + return -ENODEV; + bcm->current_core->phy->connected = 1; + + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + flags |= (0x800 << 18); + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); + dprintk(KERN_INFO PFX "PHY connected\n"); + } else { + if (!(flags & 0x00020000)) + return -ENODEV; + bcm->current_core->phy->connected = 0; + + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); + flags &= ~(0x800 << 18); + bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); + dprintk(KERN_INFO PFX "PHY disconnected\n"); + } + + return 0; +} + +/* intialize B PHY power control + * as described in http://bcm-specs.sipsolutions.net/InitPowerControl + */ +static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 saved_batt = 0, saved_ratt = 0, saved_txctl1 = 0; + int must_reset_txpower = 0; + + assert(phy->type != BCM43xx_PHYTYPE_A); + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && + (bcm->board_type == 0x0416)) + return; + + bcm43xx_write16(bcm, 0x03E6, bcm43xx_read16(bcm, 0x03E6) & 0xFFDF); + bcm43xx_phy_write(bcm, 0x0028, 0x8018); + + if (phy->type == BCM43xx_PHYTYPE_G) { + if (!phy->connected) + return; + bcm43xx_phy_write(bcm, 0x047A, 0xC111); + } + if (phy->savedpctlreg != 0xFFFF) + return; + + if (phy->type == BCM43xx_PHYTYPE_B && + phy->rev >= 2 && + radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0076, + bcm43xx_radio_read16(bcm, 0x0076) | 0x0084); + } else { + saved_batt = radio->txpower[0]; + saved_ratt = radio->txpower[1]; + saved_txctl1 = radio->txpower[2]; + if ((radio->revision >= 6) && (radio->revision <= 8) + && /*FIXME: incomplete specs for 5 < revision < 9 */ 0) + bcm43xx_radio_set_txpower_bg(bcm, 0xB, 0x1F, 0); + else + bcm43xx_radio_set_txpower_bg(bcm, 0xB, 9, 0); + must_reset_txpower = 1; + } + bcm43xx_dummy_transmission(bcm); + + phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_PCTL); + + if (must_reset_txpower) + bcm43xx_radio_set_txpower_bg(bcm, saved_batt, saved_ratt, saved_txctl1); + else + bcm43xx_radio_write16(bcm, 0x0076, bcm43xx_radio_read16(bcm, 0x0076) & 0xFF7B); + bcm43xx_radio_clear_tssi(bcm); +} + +static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 offset = 0x0000; + + if (phy->rev == 1) + offset = 0x4C00; + + bcm43xx_ilt_write16(bcm, offset, 0x00FE); + bcm43xx_ilt_write16(bcm, offset + 1, 0x000D); + bcm43xx_ilt_write16(bcm, offset + 2, 0x0013); + bcm43xx_ilt_write16(bcm, offset + 3, 0x0019); + + if (phy->rev == 1) { + bcm43xx_ilt_write16(bcm, 0x1800, 0x2710); + bcm43xx_ilt_write16(bcm, 0x1801, 0x9B83); + bcm43xx_ilt_write16(bcm, 0x1802, 0x9B83); + bcm43xx_ilt_write16(bcm, 0x1803, 0x0F8D); + bcm43xx_phy_write(bcm, 0x0455, 0x0004); + } + + bcm43xx_phy_write(bcm, 0x04A5, (bcm43xx_phy_read(bcm, 0x04A5) & 0x00FF) | 0x5700); + bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xFF80) | 0x000F); + bcm43xx_phy_write(bcm, 0x041A, (bcm43xx_phy_read(bcm, 0x041A) & 0xC07F) | 0x2B80); + bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xF0FF) | 0x0300); + + bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0008); + + bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFF0) | 0x0008); + bcm43xx_phy_write(bcm, 0x04A1, (bcm43xx_phy_read(bcm, 0x04A1) & 0xF0FF) | 0x0600); + bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0700); + bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0100); + + if (phy->rev == 1) + bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x0007); + + bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xFF00) | 0x001C); + bcm43xx_phy_write(bcm, 0x0488, (bcm43xx_phy_read(bcm, 0x0488) & 0xC0FF) | 0x0200); + bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0xFF00) | 0x001C); + bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xFF00) | 0x0020); + bcm43xx_phy_write(bcm, 0x0489, (bcm43xx_phy_read(bcm, 0x0489) & 0xC0FF) | 0x0200); + bcm43xx_phy_write(bcm, 0x0482, (bcm43xx_phy_read(bcm, 0x0482) & 0xFF00) | 0x002E); + bcm43xx_phy_write(bcm, 0x0496, (bcm43xx_phy_read(bcm, 0x0496) & 0x00FF) | 0x1A00); + bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0xFF00) | 0x0028); + bcm43xx_phy_write(bcm, 0x0481, (bcm43xx_phy_read(bcm, 0x0481) & 0x00FF) | 0x2C00); + + if (phy->rev == 1) { + bcm43xx_phy_write(bcm, 0x0430, 0x092B); + bcm43xx_phy_write(bcm, 0x041B, (bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1) | 0x0002); + } else { + bcm43xx_phy_write(bcm, 0x041B, bcm43xx_phy_read(bcm, 0x041B) & 0xFFE1); + bcm43xx_phy_write(bcm, 0x041F, 0x287A); + bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0xFFF0) | 0x0004); + } + + if (phy->rev > 2) { + bcm43xx_phy_write(bcm, 0x0422, 0x287A); + bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000); + } + + bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874); + bcm43xx_phy_write(bcm, 0x048E, 0x1C00); + + if (phy->rev == 1) { + bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600); + bcm43xx_phy_write(bcm, 0x048B, 0x005E); + bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E); + bcm43xx_phy_write(bcm, 0x048D, 0x0002); + } + + bcm43xx_ilt_write16(bcm, offset + 0x0800, 0); + bcm43xx_ilt_write16(bcm, offset + 0x0801, 7); + bcm43xx_ilt_write16(bcm, offset + 0x0802, 16); + bcm43xx_ilt_write16(bcm, offset + 0x0803, 28); +} + +static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 i; + + assert(phy->type == BCM43xx_PHYTYPE_G); + if (phy->rev == 1) { + bcm43xx_phy_write(bcm, 0x0406, 0x4F19); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340); + bcm43xx_phy_write(bcm, 0x042C, 0x005A); + bcm43xx_phy_write(bcm, 0x0427, 0x001A); + + for (i = 0; i < BCM43xx_ILT_FINEFREQG_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]); + for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]); + for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); + } else { + /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */ + bcm43xx_nrssi_hw_write(bcm, 0xBA98, (s16)0x7654); + + if (phy->rev == 2) { + bcm43xx_phy_write(bcm, 0x04C0, 0x1861); + bcm43xx_phy_write(bcm, 0x04C1, 0x0271); + } else if (phy->rev > 2) { + bcm43xx_phy_write(bcm, 0x04C0, 0x0098); + bcm43xx_phy_write(bcm, 0x04C1, 0x0070); + bcm43xx_phy_write(bcm, 0x04C9, 0x0080); + } + bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x800); + + for (i = 0; i < 64; i++) + bcm43xx_ilt_write16(bcm, 0x4000 + i, i); + for (i = 0; i < BCM43xx_ILT_NOISEG2_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noiseg2[i]); + } + + if (phy->rev <= 2) + for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]); + else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200)) + for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]); + else + for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg2[i]); + + if (phy->rev == 2) + for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); + else if ((phy->rev > 2) && (phy->rev <= 7)) + for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]); + + if (phy->rev == 1) { + for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); + for (i = 0; i < 4; i++) { + bcm43xx_ilt_write16(bcm, 0x5404 + i, 0x0020); + bcm43xx_ilt_write16(bcm, 0x5408 + i, 0x0020); + bcm43xx_ilt_write16(bcm, 0x540C + i, 0x0020); + bcm43xx_ilt_write16(bcm, 0x5410 + i, 0x0020); + } + bcm43xx_phy_agcsetup(bcm); + + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && + (bcm->board_type == 0x0416) && + (bcm->board_revision == 0x0017)) + return; + + bcm43xx_ilt_write16(bcm, 0x5001, 0x0002); + bcm43xx_ilt_write16(bcm, 0x5002, 0x0001); + } else { + for (i = 0; i <= 0x2F; i++) + bcm43xx_ilt_write16(bcm, 0x1000 + i, 0x0820); + bcm43xx_phy_agcsetup(bcm); + bcm43xx_phy_read(bcm, 0x0400); /* dummy read */ + bcm43xx_phy_write(bcm, 0x0403, 0x1000); + bcm43xx_ilt_write16(bcm, 0x3C02, 0x000F); + bcm43xx_ilt_write16(bcm, 0x3C03, 0x0014); + + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && + (bcm->board_type == 0x0416) && + (bcm->board_revision == 0x0017)) + return; + + bcm43xx_ilt_write16(bcm, 0x0401, 0x0002); + bcm43xx_ilt_write16(bcm, 0x0402, 0x0001); + } +} + +/* Initialize the noisescaletable for APHY */ +static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + int i; + + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, 0x1400); + for (i = 0; i < 12; i++) { + if (phy->rev == 2) + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767); + else + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323); + } + if (phy->rev == 2) + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6700); + else + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2300); + for (i = 0; i < 11; i++) { + if (phy->rev == 2) + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x6767); + else + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x2323); + } + if (phy->rev == 2) + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0067); + else + bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, 0x0023); +} + +static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) +{ + u16 i; + + assert(bcm->current_core->phy->type == BCM43xx_PHYTYPE_A); + switch (bcm->current_core->phy->rev) { + case 2: + bcm43xx_phy_write(bcm, 0x008E, 0x3800); + bcm43xx_phy_write(bcm, 0x0035, 0x03FF); + bcm43xx_phy_write(bcm, 0x0036, 0x0400); + + bcm43xx_ilt_write16(bcm, 0x3807, 0x0051); + + bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); + bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); + bcm43xx_ilt_write16(bcm, 0x3C0C, 0x07BF); + bcm43xx_radio_write16(bcm, 0x0002, 0x07BF); + + bcm43xx_phy_write(bcm, 0x0024, 0x4680); + bcm43xx_phy_write(bcm, 0x0020, 0x0003); + bcm43xx_phy_write(bcm, 0x001D, 0x0F40); + bcm43xx_phy_write(bcm, 0x001F, 0x1C00); + + bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400); + bcm43xx_phy_write(bcm, 0x002B, bcm43xx_phy_read(bcm, 0x002B) & 0xFBFF); + bcm43xx_phy_write(bcm, 0x008E, 0x58C1); + + bcm43xx_ilt_write16(bcm, 0x0803, 0x000F); + bcm43xx_ilt_write16(bcm, 0x0804, 0x001F); + bcm43xx_ilt_write16(bcm, 0x0805, 0x002A); + bcm43xx_ilt_write16(bcm, 0x0805, 0x0030); + bcm43xx_ilt_write16(bcm, 0x0807, 0x003A); + + bcm43xx_ilt_write16(bcm, 0x0000, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0001, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0002, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0003, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0004, 0x0015); + bcm43xx_ilt_write16(bcm, 0x0005, 0x0015); + bcm43xx_ilt_write16(bcm, 0x0006, 0x0019); + + bcm43xx_ilt_write16(bcm, 0x0404, 0x0003); + bcm43xx_ilt_write16(bcm, 0x0405, 0x0003); + bcm43xx_ilt_write16(bcm, 0x0406, 0x0007); + + for (i = 0; i < 16; i++) + bcm43xx_ilt_write16(bcm, 0x4000 + i, (0x8 + i) & 0x000F); + + bcm43xx_ilt_write16(bcm, 0x3003, 0x1044); + bcm43xx_ilt_write16(bcm, 0x3004, 0x7201); + bcm43xx_ilt_write16(bcm, 0x3006, 0x0040); + bcm43xx_ilt_write16(bcm, 0x3001, (bcm43xx_ilt_read16(bcm, 0x3001) & 0x0010) | 0x0008); + + for (i = 0; i < BCM43xx_ILT_FINEFREQA_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]); + for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]); + for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); + bcm43xx_phy_init_noisescaletbl(bcm); + for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); + break; + case 3: + for (i = 0; i < 64; i++) + bcm43xx_ilt_write16(bcm, 0x4000 + i, i); + + bcm43xx_ilt_write16(bcm, 0x3807, 0x0051); + + bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); + bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); + bcm43xx_radio_write16(bcm, 0x0002, 0x07BF); + + bcm43xx_phy_write(bcm, 0x0024, 0x4680); + bcm43xx_phy_write(bcm, 0x0020, 0x0003); + bcm43xx_phy_write(bcm, 0x001D, 0x0F40); + bcm43xx_phy_write(bcm, 0x001F, 0x1C00); + bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400); + + bcm43xx_ilt_write16(bcm, 0x3001, (bcm43xx_ilt_read16(bcm, 0x3001) & 0x0010) | 0x0008); + for (i = 0; i < BCM43xx_ILT_NOISEA3_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noisea3[i]); + bcm43xx_phy_init_noisescaletbl(bcm); + for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) + bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); + + bcm43xx_phy_write(bcm, 0x0003, 0x1808); + + bcm43xx_ilt_write16(bcm, 0x0803, 0x000F); + bcm43xx_ilt_write16(bcm, 0x0804, 0x001F); + bcm43xx_ilt_write16(bcm, 0x0805, 0x002A); + bcm43xx_ilt_write16(bcm, 0x0805, 0x0030); + bcm43xx_ilt_write16(bcm, 0x0807, 0x003A); + + bcm43xx_ilt_write16(bcm, 0x0000, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0001, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0002, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0003, 0x0013); + bcm43xx_ilt_write16(bcm, 0x0004, 0x0015); + bcm43xx_ilt_write16(bcm, 0x0005, 0x0015); + bcm43xx_ilt_write16(bcm, 0x0006, 0x0019); + + bcm43xx_ilt_write16(bcm, 0x0404, 0x0003); + bcm43xx_ilt_write16(bcm, 0x0405, 0x0003); + bcm43xx_ilt_write16(bcm, 0x0406, 0x0007); + + bcm43xx_ilt_write16(bcm, 0x3C02, 0x000F); + bcm43xx_ilt_write16(bcm, 0x3C03, 0x0014); + break; + default: + assert(0); + } +} + +/* Initialize APHY. This is also called for the GPHY in some cases. */ +static void bcm43xx_phy_inita(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 tval; + + if (phy->type == BCM43xx_PHYTYPE_A) { + bcm43xx_phy_setupa(bcm); + } else { + bcm43xx_phy_setupg(bcm); + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) + bcm43xx_phy_write(bcm, 0x046E, 0x03CF); + return; + } + + bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS, + (bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) & 0xF83C) | 0x0340); + bcm43xx_phy_write(bcm, 0x0034, 0x0001); + + TODO();//TODO: RSSI AGC + bcm43xx_phy_write(bcm, BCM43xx_PHY_A_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_A_CRS) | (1 << 14)); + bcm43xx_radio_init2060(bcm); + + if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) + && ((bcm->board_type == 0x0416) || (bcm->board_type == 0x040A))) { + if (bcm->current_core->radio->lofcal == 0xFFFF) { + TODO();//TODO: LOF Cal + bcm43xx_radio_set_tx_iq(bcm); + } else + bcm43xx_radio_write16(bcm, 0x001E, bcm->current_core->radio->lofcal); + } + + bcm43xx_phy_write(bcm, 0x007A, 0xF111); + + if (phy->savedpctlreg == 0xFFFF) { + bcm43xx_radio_write16(bcm, 0x0019, 0x0000); + bcm43xx_radio_write16(bcm, 0x0017, 0x0020); + + tval = bcm43xx_ilt_read16(bcm, 0x3001); + if (phy->rev == 1) { + bcm43xx_ilt_write16(bcm, 0x3001, + (bcm43xx_ilt_read16(bcm, 0x3001) & 0xFF87) + | 0x0058); + } else { + bcm43xx_ilt_write16(bcm, 0x3001, + (bcm43xx_ilt_read16(bcm, 0x3001) & 0xFFC3) + | 0x002C); + } + bcm43xx_dummy_transmission(bcm); + phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_A_PCTL); + bcm43xx_ilt_write16(bcm, 0x3001, tval); + + bcm43xx_radio_set_txpower_a(bcm, 0x0018); + } + bcm43xx_radio_clear_tssi(bcm); +} + +static void bcm43xx_phy_initb2(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 offset, val; + + bcm43xx_write16(bcm, 0x03EC, 0x3F22); + bcm43xx_phy_write(bcm, 0x0020, 0x301C); + bcm43xx_phy_write(bcm, 0x0026, 0x0000); + bcm43xx_phy_write(bcm, 0x0030, 0x00C6); + bcm43xx_phy_write(bcm, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + bcm43xx_phy_write(bcm, offset, val); + val -= 0x0202; + } + bcm43xx_phy_write(bcm, 0x03E4, 0x3000); + if (radio->channel == 0xFF) + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); + else + bcm43xx_radio_selectchannel(bcm, radio->channel, 0); + if (radio->version != 0x2050) { + bcm43xx_radio_write16(bcm, 0x0075, 0x0080); + bcm43xx_radio_write16(bcm, 0x0079, 0x0081); + } + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); + bcm43xx_radio_write16(bcm, 0x007A, 0x000F); + bcm43xx_phy_write(bcm, 0x0038, 0x0677); + bcm43xx_radio_init2050(bcm); + } + bcm43xx_phy_write(bcm, 0x0014, 0x0080); + bcm43xx_phy_write(bcm, 0x0032, 0x00CA); + bcm43xx_phy_write(bcm, 0x0032, 0x00CC); + bcm43xx_phy_write(bcm, 0x0035, 0x07C2); + bcm43xx_phy_lo_b_measure(bcm); + bcm43xx_phy_write(bcm, 0x0026, 0xCC00); + if (radio->version != 0x2050) + bcm43xx_phy_write(bcm, 0x0026, 0xCE00); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1000); + bcm43xx_phy_write(bcm, 0x002A, 0x88A3); + if (radio->version != 0x2050) + bcm43xx_phy_write(bcm, 0x002A, 0x88C2); + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); + bcm43xx_phy_init_pctl(bcm); +} + +static void bcm43xx_phy_initb4(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 offset, val; + + bcm43xx_write16(bcm, 0x03EC, 0x3F22); + bcm43xx_phy_write(bcm, 0x0020, 0x301C); + bcm43xx_phy_write(bcm, 0x0026, 0x0000); + bcm43xx_phy_write(bcm, 0x0030, 0x00C6); + bcm43xx_phy_write(bcm, 0x0088, 0x3E00); + val = 0x3C3D; + for (offset = 0x0089; offset < 0x00A7; offset++) { + bcm43xx_phy_write(bcm, offset, val); + val -= 0x0202; + } + bcm43xx_phy_write(bcm, 0x03E4, 0x3000); + if (radio->channel == 0xFF) + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); + else + bcm43xx_radio_selectchannel(bcm, radio->channel, 0); + if (radio->version != 0x2050) { + bcm43xx_radio_write16(bcm, 0x0075, 0x0080); + bcm43xx_radio_write16(bcm, 0x0079, 0x0081); + } + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); + bcm43xx_radio_write16(bcm, 0x007A, 0x000F); + bcm43xx_phy_write(bcm, 0x0038, 0x0677); + bcm43xx_radio_init2050(bcm); + } + bcm43xx_phy_write(bcm, 0x0014, 0x0080); + bcm43xx_phy_write(bcm, 0x0032, 0x00CA); + if (radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x0032, 0x00E0); + bcm43xx_phy_write(bcm, 0x0035, 0x07C2); + + bcm43xx_phy_lo_b_measure(bcm); + + bcm43xx_phy_write(bcm, 0x0026, 0xCC00); + if (radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x0026, 0xCE00); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x1100); + bcm43xx_phy_write(bcm, 0x002A, 0x88A3); + if (radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x002A, 0x88C2); + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + bcm43xx_calc_nrssi_slope(bcm); + bcm43xx_calc_nrssi_threshold(bcm); + } + bcm43xx_phy_init_pctl(bcm); +} + +static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 offset; + + if (phy->version == 1 && + radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) + | 0x0050); + } + if ((bcm->board_vendor != PCI_VENDOR_ID_BROADCOM) && + (bcm->board_type != 0x0416)) { + for (offset = 0x00A8 ; offset < 0x00C7; offset++) { + bcm43xx_phy_write(bcm, offset, + (bcm43xx_phy_read(bcm, offset) + 0x2020) + & 0x3F3F); + } + } + bcm43xx_phy_write(bcm, 0x0035, + (bcm43xx_phy_read(bcm, 0x0035) & 0xF0FF) + | 0x0700); + if (radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x0038, 0x0667); + + if (phy->connected) { + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) + | 0x0020); + bcm43xx_radio_write16(bcm, 0x0051, + bcm43xx_radio_read16(bcm, 0x0051) + | 0x0004); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, 0x0000); + + bcm43xx_phy_write(bcm, 0x0802, bcm43xx_phy_read(bcm, 0x0802) | 0x0100); + bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x2000); + + bcm43xx_phy_write(bcm, 0x001C, 0x186A); + + bcm43xx_phy_write(bcm, 0x0013, (bcm43xx_phy_read(bcm, 0x0013) & 0x00FF) | 0x1900); + bcm43xx_phy_write(bcm, 0x0035, (bcm43xx_phy_read(bcm, 0x0035) & 0xFFC0) | 0x0064); + bcm43xx_phy_write(bcm, 0x005D, (bcm43xx_phy_read(bcm, 0x005D) & 0xFF80) | 0x000A); + } + + if (bcm->bad_frames_preempt) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | (1 << 11)); + } + + if (phy->version == 1 && radio->version == 0x2050) { + bcm43xx_phy_write(bcm, 0x0026, 0xCE00); + bcm43xx_phy_write(bcm, 0x0021, 0x3763); + bcm43xx_phy_write(bcm, 0x0022, 0x1BC3); + bcm43xx_phy_write(bcm, 0x0023, 0x06F9); + bcm43xx_phy_write(bcm, 0x0024, 0x037E); + } else + bcm43xx_phy_write(bcm, 0x0026, 0xCC00); + bcm43xx_phy_write(bcm, 0x0030, 0x00C6); + bcm43xx_write16(bcm, 0x03EC, 0x3F22); + + if (phy->version == 1 && radio->version == 0x2050) + bcm43xx_phy_write(bcm, 0x0020, 0x3E1C); + else + bcm43xx_phy_write(bcm, 0x0020, 0x301C); + + if (phy->version == 0) + bcm43xx_write16(bcm, 0x03E4, 0x3000); + + /* Force to channel 7, even if not supported. */ + bcm43xx_radio_selectchannel(bcm, 7, 0); + + if (radio->version != 0x2050) { + bcm43xx_radio_write16(bcm, 0x0075, 0x0080); + bcm43xx_radio_write16(bcm, 0x0079, 0x0081); + } + + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); + + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); + } + + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); + + bcm43xx_radio_write16(bcm, 0x007A, bcm43xx_radio_read16(bcm, 0x007A) | 0x0007); + + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); + + bcm43xx_phy_write(bcm, 0x0014, 0x0080); + bcm43xx_phy_write(bcm, 0x0032, 0x00CA); + bcm43xx_phy_write(bcm, 0x88A3, 0x002A); + + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); + + if (radio->version == 0x2050) + bcm43xx_radio_write16(bcm, 0x005D, 0x000D); + + bcm43xx_write16(bcm, 0x03E4, (bcm43xx_read16(bcm, 0x03E4) & 0xFFC0) | 0x0004); +} + +static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 offset, val; + + bcm43xx_phy_write(bcm, 0x003E, 0x817A); + bcm43xx_radio_write16(bcm, 0x007A, + (bcm43xx_radio_read16(bcm, 0x007A) | 0x0058)); + if ((radio->manufact == 0x17F) && + (radio->version == 0x2050) && + (radio->revision == 3 || + radio->revision == 4 || + radio->revision == 5)) { + bcm43xx_radio_write16(bcm, 0x0051, 0x001F); + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); + bcm43xx_radio_write16(bcm, 0x0053, 0x005B); + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); + bcm43xx_radio_write16(bcm, 0x005B, 0x0088); + bcm43xx_radio_write16(bcm, 0x005D, 0x0088); + bcm43xx_radio_write16(bcm, 0x005E, 0x0088); + bcm43xx_radio_write16(bcm, 0x007D, 0x0088); + } + if ((radio->manufact == 0x17F) && + (radio->version == 0x2050) && + (radio->revision == 6)) { + bcm43xx_radio_write16(bcm, 0x0051, 0x0000); + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); + bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); + bcm43xx_radio_write16(bcm, 0x005B, 0x008B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B5); + bcm43xx_radio_write16(bcm, 0x005D, 0x0088); + bcm43xx_radio_write16(bcm, 0x005E, 0x0088); + bcm43xx_radio_write16(bcm, 0x007D, 0x0088); + bcm43xx_radio_write16(bcm, 0x007C, 0x0001); + bcm43xx_radio_write16(bcm, 0x007E, 0x0008); + } + if ((radio->manufact == 0x17F) && + (radio->version == 0x2050) && + (radio->revision == 7)) { + bcm43xx_radio_write16(bcm, 0x0051, 0x0000); + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); + bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); + bcm43xx_radio_write16(bcm, 0x005B, 0x00A8); + bcm43xx_radio_write16(bcm, 0x005C, 0x0075); + bcm43xx_radio_write16(bcm, 0x005D, 0x00F5); + bcm43xx_radio_write16(bcm, 0x005E, 0x00B8); + bcm43xx_radio_write16(bcm, 0x007D, 0x00E8); + bcm43xx_radio_write16(bcm, 0x007C, 0x0001); + bcm43xx_radio_write16(bcm, 0x007E, 0x0008); + bcm43xx_radio_write16(bcm, 0x007B, 0x0000); + } + if ((radio->manufact == 0x17F) && + (radio->version == 0x2050) && + (radio->revision == 8)) { + bcm43xx_radio_write16(bcm, 0x0051, 0x0000); + bcm43xx_radio_write16(bcm, 0x0052, 0x0040); + bcm43xx_radio_write16(bcm, 0x0053, 0x00B7); + bcm43xx_radio_write16(bcm, 0x0054, 0x0098); + bcm43xx_radio_write16(bcm, 0x005A, 0x0088); + bcm43xx_radio_write16(bcm, 0x005B, 0x006B); + bcm43xx_radio_write16(bcm, 0x005C, 0x000F); + if (bcm->sprom.boardflags & 0x8000) { + bcm43xx_radio_write16(bcm, 0x005D, 0x00FA); + bcm43xx_radio_write16(bcm, 0x005E, 0x00D8); + } else { + bcm43xx_radio_write16(bcm, 0x005D, 0x00F5); + bcm43xx_radio_write16(bcm, 0x005E, 0x00B8); + } + bcm43xx_radio_write16(bcm, 0x0073, 0x0003); + bcm43xx_radio_write16(bcm, 0x007D, 0x00A8); + bcm43xx_radio_write16(bcm, 0x007C, 0x0001); + bcm43xx_radio_write16(bcm, 0x007E, 0x0008); + } + val = 0x1E1F; + for (offset = 0x0088; offset < 0x0098; offset++) { + bcm43xx_phy_write(bcm, offset, val); + val -= 0x0202; + } + val = 0x3E3F; + for (offset = 0x0098; offset < 0x00A8; offset++) { + bcm43xx_phy_write(bcm, offset, val); + val -= 0x0202; + } + val = 0x2120; + for (offset = 0x00A8; offset < 0x00C8; offset++) { + bcm43xx_phy_write(bcm, offset, (val & 0x3F3F)); + val += 0x0202; + } + if (phy->type == BCM43xx_PHYTYPE_G) { + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0020); + bcm43xx_radio_write16(bcm, 0x0051, + bcm43xx_radio_read16(bcm, 0x0051) | 0x0004); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) | 0x0100); + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) | 0x2000); + } + + /* Force to channel 7, even if not supported. */ + bcm43xx_radio_selectchannel(bcm, 7, 0); + + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x0050, 0x0023); + udelay(40); + bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) | 0x0002)); + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + if ((bcm->current_core->radio->manufact == 0x17F) && + (bcm->current_core->radio->version == 0x2050) && + (bcm->current_core->radio->revision == 2)) { + bcm43xx_radio_write16(bcm, 0x0050, 0x0020); + bcm43xx_radio_write16(bcm, 0x005A, 0x0070); + bcm43xx_radio_write16(bcm, 0x005B, 0x007B); + bcm43xx_radio_write16(bcm, 0x005C, 0x00B0); + } + bcm43xx_radio_write16(bcm, 0x007A, + (bcm43xx_radio_read16(bcm, 0x007A) & 0x00F8) | 0x0007); + + bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 0); + + bcm43xx_phy_write(bcm, 0x0014, 0x0200); + if (radio->version == 0x2050){ + if (radio->revision == 3 || + radio->revision == 4 || + radio->revision == 5) + bcm43xx_phy_write(bcm, 0x002A, 0x8AC0); + else + bcm43xx_phy_write(bcm, 0x002A, 0x88C2); + } + bcm43xx_phy_write(bcm, 0x0038, 0x0668); + bcm43xx_radio_set_txpower_bg(bcm, 0xFFFF, 0xFFFF, 0xFFFF); + if (radio->version == 0x2050) { + if (radio->revision == 3 || + radio->revision == 4 || + radio->revision == 5) + bcm43xx_phy_write(bcm, 0x005D, bcm43xx_phy_read(bcm, 0x005D) | 0x0003); + else if (radio->revision <= 2) + bcm43xx_radio_write16(bcm, 0x005D, 0x000D); + } + + if (phy->rev == 4) + bcm43xx_phy_write(bcm, 0x0002, (bcm43xx_phy_read(bcm, 0x0002) & 0xFFC0) | 0x0004); + else + bcm43xx_write16(bcm, 0x03E4, 0x0009); + if (phy->type == BCM43xx_PHYTYPE_B) { + bcm43xx_write16(bcm, 0x03E6, 0x8140); + bcm43xx_phy_write(bcm, 0x0016, 0x5410); + bcm43xx_phy_write(bcm, 0x0017, 0xA820); + bcm43xx_phy_write(bcm, 0x0007, 0x0062); + TODO();//TODO: calibrate stuff. + bcm43xx_phy_init_pctl(bcm); + } else + bcm43xx_write16(bcm, 0x03E6, 0x0); +} + +static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 tmp; + + if (phy->rev == 1) + bcm43xx_phy_initb5(bcm); + else if (phy->rev >= 2 && phy->rev <= 7) + bcm43xx_phy_initb6(bcm); + if (phy->rev >= 2 || phy->connected) + bcm43xx_phy_inita(bcm); + + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0814, 0x0000); + bcm43xx_phy_write(bcm, 0x0815, 0x0000); + if (phy->rev == 2) + bcm43xx_phy_write(bcm, 0x0811, 0x0000); + else if (phy->rev >= 3) + bcm43xx_phy_write(bcm, 0x0811, 0x0400); + bcm43xx_phy_write(bcm, 0x0015, 0x00C0); + tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF; + if (tmp == 3) { + bcm43xx_phy_write(bcm, 0x04C2, 0x1816); + bcm43xx_phy_write(bcm, 0x04C3, 0x8606); + } else if (tmp == 4 || tmp == 5) { + bcm43xx_phy_write(bcm, 0x04C2, 0x1816); + bcm43xx_phy_write(bcm, 0x04C3, 0x8006); + bcm43xx_phy_write(bcm, 0x04CC, (bcm43xx_phy_read(bcm, 0x04CC) + & 0x00FF) | 0x1F00); + } + } + if (radio->revision <= 3 && phy->connected) + bcm43xx_phy_write(bcm, 0x047E, 0x0078); + if (radio->revision >= 6 && radio->revision <= 8) { + bcm43xx_phy_write(bcm, 0x0801, bcm43xx_phy_read(bcm, 0x0801) | 0x0080); + bcm43xx_phy_write(bcm, 0x043E, bcm43xx_phy_read(bcm, 0x043E) | 0x0004); + } + if (radio->initval == 0xFFFF) { + radio->initval = bcm43xx_radio_init2050(bcm); + bcm43xx_phy_lo_g_measure(bcm); + } else { + bcm43xx_radio_write16(bcm, 0x0078, radio->initval); + bcm43xx_radio_write16(bcm, 0x0052, + (bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0) + | radio->txpower[3]); + } + + if (phy->connected) { + bcm43xx_phy_lo_adjust(bcm, 0); + bcm43xx_phy_write(bcm, 0x080F, 0x8078); + + if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) + bcm43xx_phy_write(bcm, 0x002E, 0x807F); + else + bcm43xx_phy_write(bcm, 0x002E, 0x8075); + + if (phy->rev < 2) + bcm43xx_phy_write(bcm, 0x002F, 0x0101); + else + bcm43xx_phy_write(bcm, 0x002F, 0x0202); + } + + if ((bcm->sprom.boardflags & BCM43xx_BFL_RSSI) == 0) { + FIXME();//FIXME: 0x7FFFFFFF should be 16-bit ! + bcm43xx_nrssi_hw_update(bcm, (u16)0x7FFFFFFF); + bcm43xx_calc_nrssi_threshold(bcm); + } else if (phy->connected) { + if (radio->nrssi[0] == -1000) { + assert(radio->nrssi[1] == -1000); + bcm43xx_calc_nrssi_slope(bcm); + } else + bcm43xx_calc_nrssi_threshold(bcm); + } + bcm43xx_phy_init_pctl(bcm); +} + +static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm) +{ + int i; + u16 ret = 0; + + for (i = 0; i < 10; i++){ + bcm43xx_phy_write(bcm, 0x0015, 0xAFA0); + udelay(1); + bcm43xx_phy_write(bcm, 0x0015, 0xEFA0); + udelay(10); + bcm43xx_phy_write(bcm, 0x0015, 0xFFA0); + udelay(40); + ret += bcm43xx_phy_read(bcm, 0x002C); + } + + return ret; +} + +void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 regstack[12] = { 0 }; + u16 mls; + u16 fval; + int i, j; + + regstack[0] = bcm43xx_phy_read(bcm, 0x0015); + regstack[1] = bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0; + + if (radio->version == 0x2053) { + regstack[2] = bcm43xx_phy_read(bcm, 0x000A); + regstack[3] = bcm43xx_phy_read(bcm, 0x002A); + regstack[4] = bcm43xx_phy_read(bcm, 0x0035); + regstack[5] = bcm43xx_phy_read(bcm, 0x0003); + regstack[6] = bcm43xx_phy_read(bcm, 0x0001); + regstack[7] = bcm43xx_phy_read(bcm, 0x0030); + + regstack[8] = bcm43xx_radio_read16(bcm, 0x0043); + regstack[9] = bcm43xx_radio_read16(bcm, 0x007A); + regstack[10] = bcm43xx_read16(bcm, 0x03EC); + regstack[11] = bcm43xx_radio_read16(bcm, 0x0052) & 0x00F0; + + bcm43xx_phy_write(bcm, 0x0030, 0x00FF); + bcm43xx_write16(bcm, 0x03EC, 0x3F3F); + bcm43xx_phy_write(bcm, 0x0035, regstack[4] & 0xFF7F); + bcm43xx_radio_write16(bcm, 0x007A, regstack[9] & 0xFFF0); + } + bcm43xx_phy_write(bcm, 0x0015, 0xB000); + bcm43xx_phy_write(bcm, 0x002B, 0x0004); + + if (radio->version == 0x2053) { + bcm43xx_phy_write(bcm, 0x002B, 0x0203); + bcm43xx_phy_write(bcm, 0x002A, 0x08A3); + } + + phy->minlowsig[0] = 0xFFFF; + + for (i = 0; i < 4; i++) { + bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i); + bcm43xx_phy_lo_b_r15_loop(bcm); + } + for (i = 0; i < 10; i++) { + bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | i); + mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10; + if (mls < phy->minlowsig[0]) { + phy->minlowsig[0] = mls; + phy->minlowsigpos[0] = i; + } + } + bcm43xx_radio_write16(bcm, 0x0052, regstack[1] | phy->minlowsigpos[0]); + + phy->minlowsig[1] = 0xFFFF; + + for (i = -4; i < 5; i += 2) { + for (j = -4; j < 5; j += 2) { + if (j < 0) + fval = (0x0100 * i) + j + 0x0100; + else + fval = (0x0100 * i) + j; + bcm43xx_phy_write(bcm, 0x002F, fval); + mls = bcm43xx_phy_lo_b_r15_loop(bcm) / 10; + if (mls < phy->minlowsig[1]) { + phy->minlowsig[1] = mls; + phy->minlowsigpos[1] = fval; + } + } + } + phy->minlowsigpos[1] += 0x0101; + + bcm43xx_phy_write(bcm, 0x002F, phy->minlowsigpos[1]); + if (radio->version == 2053) { + bcm43xx_phy_write(bcm, 0x000A, regstack[2]); + bcm43xx_phy_write(bcm, 0x002A, regstack[3]); + bcm43xx_phy_write(bcm, 0x0035, regstack[4]); + bcm43xx_phy_write(bcm, 0x0003, regstack[5]); + bcm43xx_phy_write(bcm, 0x0001, regstack[6]); + bcm43xx_phy_write(bcm, 0x0030, regstack[7]); + + bcm43xx_radio_write16(bcm, 0x0043, regstack[8]); + bcm43xx_radio_write16(bcm, 0x007A, regstack[9]); + + bcm43xx_radio_write16(bcm, 0x0052, + (bcm43xx_radio_read16(bcm, 0x0052) & 0x000F) + | regstack[11]); + + bcm43xx_write16(bcm, 0x03EC, regstack[10]); + } + bcm43xx_phy_write(bcm, 0x0015, regstack[0]); +} + +static inline +u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) +{ + if (bcm->current_core->phy->connected) { + bcm43xx_phy_write(bcm, 0x15, 0xE300); + control <<= 8; + bcm43xx_phy_write(bcm, 0x0812, control | 0x00B0); + udelay(5); + bcm43xx_phy_write(bcm, 0x0812, control | 0x00B2); + udelay(2); + bcm43xx_phy_write(bcm, 0x0812, control | 0x00B3); + udelay(4); + bcm43xx_phy_write(bcm, 0x0015, 0xF300); + udelay(8); + } else { + bcm43xx_phy_write(bcm, 0x0015, control | 0xEFA0); + udelay(2); + bcm43xx_phy_write(bcm, 0x0015, control | 0xEFE0); + udelay(4); + bcm43xx_phy_write(bcm, 0x0015, control | 0xFFE0); + udelay(8); + } + + return bcm43xx_phy_read(bcm, 0x002D); +} + +static u32 bcm43xx_phy_lo_g_singledeviation(struct bcm43xx_private *bcm, u16 control) +{ + int i; + u32 ret = 0; + + for (i = 0; i < 8; i++) + ret += bcm43xx_phy_lo_g_deviation_subval(bcm, control); + + return ret; +} + +/* Write the LocalOscillator CONTROL */ +static inline +void bcm43xx_lo_write(struct bcm43xx_private *bcm, + struct bcm43xx_lopair *pair) +{ + u16 value; + + value = (u8)(pair->low); + value |= ((u8)(pair->high)) << 8; + +#ifdef CONFIG_BCM43XX_DEBUG + /* Sanity check. */ + if (pair->low < -8 || pair->low > 8 || + pair->high < -8 || pair->high > 8) { + printk(KERN_WARNING PFX + "WARNING: Writing invalid LOpair " + "(low: %d, high: %d, index: %lu)\n", + pair->low, pair->high, + (unsigned long)(pair - bcm->current_core->phy->_lo_pairs)); + dump_stack(); + } +#endif + + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, value); +} + +static inline +struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm, + u16 baseband_attenuation, + u16 radio_attenuation, + u16 tx) +{ + static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 }; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + + if (baseband_attenuation > 6) + baseband_attenuation = 6; + assert(radio_attenuation < 10); + assert(tx == 0 || tx == 3); + + if (tx == 3) { + return bcm43xx_get_lopair(phy, + radio_attenuation, + baseband_attenuation); + } + return bcm43xx_get_lopair(phy, dict[radio_attenuation], baseband_attenuation); +} + +static inline +struct bcm43xx_lopair * bcm43xx_current_lopair(struct bcm43xx_private *bcm) +{ + return bcm43xx_find_lopair(bcm, + bcm->current_core->radio->txpower[0], + bcm->current_core->radio->txpower[1], + bcm->current_core->radio->txpower[2]); +} + +/* Adjust B/G LO */ +void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed) +{ + struct bcm43xx_lopair *pair; + + if (fixed) { + /* Use fixed values. Only for initialization. */ + pair = bcm43xx_find_lopair(bcm, 2, 3, 0); + } else + pair = bcm43xx_current_lopair(bcm); + bcm43xx_lo_write(bcm, pair); +} + +static inline +void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm) +{ + u16 txctl2 = 0, i; + u32 smallest, tmp; + + bcm43xx_radio_write16(bcm, 0x0052, 0x0000); + udelay(10); + smallest = bcm43xx_phy_lo_g_singledeviation(bcm, 0); + for (i = 0; i < 16; i++) { + bcm43xx_radio_write16(bcm, 0x0052, i); + udelay(10); + tmp = bcm43xx_phy_lo_g_singledeviation(bcm, 0); + if (tmp < smallest) { + smallest = tmp; + txctl2 = i; + } + } + bcm->current_core->radio->txpower[3] = txctl2; +} + +static +void bcm43xx_phy_lo_g_state(struct bcm43xx_private *bcm, + const struct bcm43xx_lopair *in_pair, + struct bcm43xx_lopair *out_pair, + u16 r27) +{ + static const struct bcm43xx_lopair transitions[8] = { + { .high = 1, .low = 1, }, + { .high = 1, .low = 0, }, + { .high = 1, .low = -1, }, + { .high = 0, .low = -1, }, + { .high = -1, .low = -1, }, + { .high = -1, .low = 0, }, + { .high = -1, .low = 1, }, + { .high = 0, .low = 1, }, + }; + struct bcm43xx_lopair lowest_transition = { + .high = in_pair->high, + .low = in_pair->low, + }; + struct bcm43xx_lopair tmp_pair; + struct bcm43xx_lopair transition; + int i = 12; + int state = 0; + int found_lower; + int j, begin, end; + u32 lowest_deviation; + u32 tmp; + + /* Note that in_pair and out_pair can point to the same pair. Be careful. */ + + bcm43xx_lo_write(bcm, &lowest_transition); + lowest_deviation = bcm43xx_phy_lo_g_singledeviation(bcm, r27); + do { + found_lower = 0; + assert(state >= 0 && state <= 8); + if (state == 0) { + begin = 1; + end = 8; + } else if (state % 2 == 0) { + begin = state - 1; + end = state + 1; + } else { + begin = state - 2; + end = state + 2; + } + if (begin < 1) + begin += 8; + if (end > 8) + end -= 8; + + j = begin; + tmp_pair.high = lowest_transition.high; + tmp_pair.low = lowest_transition.low; + while (1) { + assert(j >= 1 && j <= 8); + transition.high = tmp_pair.high + transitions[j - 1].high; + transition.low = tmp_pair.low + transitions[j - 1].low; + if ((abs(transition.low) < 9) && (abs(transition.high) < 9)) { + bcm43xx_lo_write(bcm, &transition); + tmp = bcm43xx_phy_lo_g_singledeviation(bcm, r27); + if (tmp < lowest_deviation) { + lowest_deviation = tmp; + state = j; + found_lower = 1; + + lowest_transition.high = transition.high; + lowest_transition.low = transition.low; + } + } + if (j == end) + break; + if (j == 8) + j = 1; + else + j++; + } + } while (i-- && found_lower); + + out_pair->high = lowest_transition.high; + out_pair->low = lowest_transition.low; +} + +/* Set the baseband attenuation value on chip. */ +void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, + u16 baseband_attenuation) +{ + u16 value; + + if (bcm->current_core->phy->version == 0) { + value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0); + value |= (baseband_attenuation & 0x000F); + bcm43xx_write16(bcm, 0x03E6, value); + return; + } + + if (bcm->current_core->phy->version > 1) { + value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C; + value |= (baseband_attenuation << 2) & 0x003C; + } else { + value = bcm43xx_phy_read(bcm, 0x0060) & ~0x0078; + value |= (baseband_attenuation << 3) & 0x0078; + } + bcm43xx_phy_write(bcm, 0x0060, value); +} + +/* http://bcm-specs.sipsolutions.net/LocalOscillator/Measure */ +void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) +{ + static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; + const int is_initializing = bcm43xx_is_initializing(bcm); + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 h, i, oldi = 0, j; + struct bcm43xx_lopair control; + struct bcm43xx_lopair *tmp_control; + u16 tmp; + u16 regstack[16] = { 0 }; + u8 oldchannel; + + //XXX: What are these? + u8 r27 = 0, r31; + + oldchannel = radio->channel; + /* Setup */ + if (phy->connected) { + regstack[0] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS); + regstack[1] = bcm43xx_phy_read(bcm, 0x0802); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF); + bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC); + } + regstack[3] = bcm43xx_read16(bcm, 0x03E2); + bcm43xx_write16(bcm, 0x03E2, regstack[3] | 0x8000); + regstack[4] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); + regstack[5] = bcm43xx_phy_read(bcm, 0x15); + regstack[6] = bcm43xx_phy_read(bcm, 0x2A); + regstack[7] = bcm43xx_phy_read(bcm, 0x35); + regstack[8] = bcm43xx_phy_read(bcm, 0x60); + regstack[9] = bcm43xx_radio_read16(bcm, 0x43); + regstack[10] = bcm43xx_radio_read16(bcm, 0x7A); + regstack[11] = bcm43xx_radio_read16(bcm, 0x52); + if (phy->connected) { + regstack[12] = bcm43xx_phy_read(bcm, 0x0811); + regstack[13] = bcm43xx_phy_read(bcm, 0x0812); + regstack[14] = bcm43xx_phy_read(bcm, 0x0814); + regstack[15] = bcm43xx_phy_read(bcm, 0x0815); + } + bcm43xx_radio_selectchannel(bcm, 6, 0); + if (phy->connected) { + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0] & 0x7FFF); + bcm43xx_phy_write(bcm, 0x0802, regstack[1] & 0xFFFC); + bcm43xx_dummy_transmission(bcm); + } + bcm43xx_radio_write16(bcm, 0x0043, 0x0006); + + bcm43xx_phy_set_baseband_attenuation(bcm, 2); + + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, 0x0000); + bcm43xx_phy_write(bcm, 0x002E, 0x007F); + bcm43xx_phy_write(bcm, 0x080F, 0x0078); + bcm43xx_phy_write(bcm, 0x0035, regstack[7] & ~(1 << 7)); + bcm43xx_radio_write16(bcm, 0x007A, regstack[10] & 0xFFF0); + bcm43xx_phy_write(bcm, 0x002B, 0x0203); + bcm43xx_phy_write(bcm, 0x002A, 0x08A3); + if (phy->connected) { + bcm43xx_phy_write(bcm, 0x0814, regstack[14] | 0x0003); + bcm43xx_phy_write(bcm, 0x0815, regstack[15] & 0xFFFC); + bcm43xx_phy_write(bcm, 0x0811, 0x01B3); + bcm43xx_phy_write(bcm, 0x0812, 0x00B2); + } + if (is_initializing) + bcm43xx_phy_lo_g_measure_txctl2(bcm); + bcm43xx_phy_write(bcm, 0x080F, 0x8078); + + /* Measure */ + control.low = 0; + control.high = 0; + for (h = 0; h < 10; h++) { + /* Loop over each possible RadioAttenuation (0-9) */ + i = pairorder[h]; + if (is_initializing) { + if (i == 3) { + control.low = 0; + control.high = 0; + } else if (((i % 2 == 1) && (oldi % 2 == 1)) || + ((i % 2 == 0) && (oldi % 2 == 0))) { + tmp_control = bcm43xx_get_lopair(phy, oldi, 0); + memcpy(&control, tmp_control, sizeof(control)); + } else { + tmp_control = bcm43xx_get_lopair(phy, 3, 0); + memcpy(&control, tmp_control, sizeof(control)); + } + } + /* Loop over each possible BasebandAttenuation/2 */ + for (j = 0; j < 4; j++) { + if (is_initializing) { + tmp = i * 2 + j; + r27 = 0; + r31 = 0; + if (tmp > 14) { + r31 = 1; + if (tmp > 17) + r27 = 1; + if (tmp > 19) + r27 = 2; + } + } else { + tmp_control = bcm43xx_get_lopair(phy, i, j * 2); + if (!tmp_control->used) + continue; + memcpy(&control, tmp_control, sizeof(control)); + r27 = 3; + r31 = 0; + } + bcm43xx_radio_write16(bcm, 0x43, i); + bcm43xx_radio_write16(bcm, 0x52, + radio->txpower[3]); + udelay(10); + + bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); + + tmp = (regstack[10] & 0xFFF0); + if (r31) + tmp |= 0x0008; + bcm43xx_radio_write16(bcm, 0x007A, tmp); + + tmp_control = bcm43xx_get_lopair(phy, i, j * 2); + bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27); + } + oldi = i; + } + /* Loop over each possible RadioAttenuation (10-13) */ + for (i = 10; i < 14; i++) { + /* Loop over each possible BasebandAttenuation/2 */ + for (j = 0; j < 4; j++) { + if (is_initializing) { + tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2); + memcpy(&control, tmp_control, sizeof(control)); + tmp = (i - 9) * 2 + j - 5;//FIXME: This is wrong, as the following if statement can never trigger. + r27 = 0; + r31 = 0; + if (tmp > 14) { + r31 = 1; + if (tmp > 17) + r27 = 1; + if (tmp > 19) + r27 = 2; + } + } else { + tmp_control = bcm43xx_get_lopair(phy, i - 9, j * 2); + if (!tmp_control->used) + continue; + memcpy(&control, tmp_control, sizeof(control)); + r27 = 3; + r31 = 0; + } + bcm43xx_radio_write16(bcm, 0x43, i - 9); + bcm43xx_radio_write16(bcm, 0x52, + radio->txpower[3] + | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above? + udelay(10); + + bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); + + tmp = (regstack[10] & 0xFFF0); + if (r31) + tmp |= 0x0008; + bcm43xx_radio_write16(bcm, 0x7A, tmp); + + tmp_control = bcm43xx_get_lopair(phy, i, j * 2); + bcm43xx_phy_lo_g_state(bcm, &control, tmp_control, r27); + } + } + + /* Restoration */ + if (phy->connected) { + bcm43xx_phy_write(bcm, 0x0015, 0xE300); + bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA0); + udelay(5); + bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA2); + udelay(2); + bcm43xx_phy_write(bcm, 0x0812, (r27 << 8) | 0xA3); + } else + bcm43xx_phy_write(bcm, 0x0015, r27 | 0xEFA0); + bcm43xx_phy_lo_adjust(bcm, is_initializing); + bcm43xx_phy_write(bcm, 0x002E, 0x807F); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x002F, 0x0202); + else + bcm43xx_phy_write(bcm, 0x002F, 0x0101); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, regstack[4]); + bcm43xx_phy_write(bcm, 0x0015, regstack[5]); + bcm43xx_phy_write(bcm, 0x002A, regstack[6]); + bcm43xx_phy_write(bcm, 0x0035, regstack[7]); + bcm43xx_phy_write(bcm, 0x0060, regstack[8]); + bcm43xx_radio_write16(bcm, 0x0043, regstack[9]); + bcm43xx_radio_write16(bcm, 0x007A, regstack[10]); + regstack[11] &= 0x00F0; + regstack[11] |= (bcm43xx_radio_read16(bcm, 0x52) & 0x000F); + bcm43xx_radio_write16(bcm, 0x52, regstack[11]); + bcm43xx_write16(bcm, 0x03E2, regstack[3]); + if (phy->connected) { + bcm43xx_phy_write(bcm, 0x0811, regstack[12]); + bcm43xx_phy_write(bcm, 0x0812, regstack[13]); + bcm43xx_phy_write(bcm, 0x0814, regstack[14]); + bcm43xx_phy_write(bcm, 0x0815, regstack[15]); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, regstack[0]); + bcm43xx_phy_write(bcm, 0x0802, regstack[1]); + } + bcm43xx_radio_selectchannel(bcm, oldchannel, 1); + +#ifdef CONFIG_BCM43XX_DEBUG + { + /* Sanity check for all lopairs. */ + for (i = 0; i < BCM43xx_LO_COUNT; i++) { + tmp_control = phy->_lo_pairs + i; + if (tmp_control->low < -8 || tmp_control->low > 8 || + tmp_control->high < -8 || tmp_control->high > 8) { + printk(KERN_WARNING PFX + "WARNING: Invalid LOpair (low: %d, high: %d, index: %d)\n", + tmp_control->low, tmp_control->high, i); + } + } + } +#endif /* CONFIG_BCM43XX_DEBUG */ +} + +static +void bcm43xx_phy_lo_mark_current_used(struct bcm43xx_private *bcm) +{ + struct bcm43xx_lopair *pair; + + pair = bcm43xx_current_lopair(bcm); + pair->used = 1; +} + +void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_lopair *pair; + int i; + + for (i = 0; i < BCM43xx_LO_COUNT; i++) { + pair = phy->_lo_pairs + i; + pair->used = 0; + } +} + +/* http://bcm-specs.sipsolutions.net/EstimatePowerOut + * This function converts a TSSI value to dBm in Q5.2 + */ +static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + s8 dbm = 0; + s32 tmp; + + tmp = phy->idle_tssi; + tmp += tssi; + tmp -= phy->savedpctlreg; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + tmp += 0x80; + tmp = limit_value(tmp, 0x00, 0xFF); + dbm = phy->tssi2dbm[tmp]; + TODO(); //TODO: There's a FIXME on the specs + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + tmp = limit_value(tmp, 0x00, 0x3F); + dbm = phy->tssi2dbm[tmp]; + break; + default: + assert(0); + } + + return dbm; +} + +/* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ +void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + + if (phy->savedpctlreg == 0xFFFF) + return; + if ((bcm->board_type == 0x0416) && + (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM)) + return; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: { + + TODO(); //TODO: Nothing for A PHYs yet :-/ + + break; + } + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: { + u16 tmp; + u16 txpower; + s8 v0, v1, v2, v3; + s8 average; + u8 max_pwr; + s16 desired_pwr, estimated_pwr, pwr_adjust; + s16 radio_att_delta, baseband_att_delta; + s16 radio_attenuation, baseband_attenuation; + unsigned long phylock_flags; + + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0058); + v0 = (s8)(tmp & 0x00FF); + v1 = (s8)((tmp & 0xFF00) >> 8); + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005A); + v2 = (s8)(tmp & 0x00FF); + v3 = (s8)((tmp & 0xFF00) >> 8); + tmp = 0; + + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) { + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0070); + v0 = (s8)(tmp & 0x00FF); + v1 = (s8)((tmp & 0xFF00) >> 8); + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0072); + v2 = (s8)(tmp & 0x00FF); + v3 = (s8)((tmp & 0xFF00) >> 8); + if (v0 == 0x7F || v1 == 0x7F || v2 == 0x7F || v3 == 0x7F) + return; + v0 = (v0 + 0x20) & 0x3F; + v1 = (v1 + 0x20) & 0x3F; + v2 = (v2 + 0x20) & 0x3F; + v3 = (v3 + 0x20) & 0x3F; + tmp = 1; + } + bcm43xx_radio_clear_tssi(bcm); + + average = (v0 + v1 + v2 + v3 + 2) / 4; + + if (tmp && (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x005E) & 0x8)) + average -= 13; + + estimated_pwr = bcm43xx_phy_estimate_power_out(bcm, average); + + max_pwr = bcm->sprom.maxpower_bgphy; + + if ((bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) && + (phy->type == BCM43xx_PHYTYPE_G)) + max_pwr -= 0x3; + + /*TODO: + max_pwr = min(REG - bcm->sprom.antennagain_bgphy - 0x6, max_pwr) + where REG is the max power as per the regulatory domain + */ + + /*TODO: Get desired_pwr from wx_handlers or the stack + limit_value(desired_pwr, 0, max_pwr); + */ + + desired_pwr = max_pwr; /* remove this when we have a real desired_pwr */ + + pwr_adjust = desired_pwr - estimated_pwr; + + radio_att_delta = -(pwr_adjust + 7) >> 3; + baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta); + if ((radio_att_delta == 0) && (baseband_att_delta == 0)) { + bcm43xx_phy_lo_mark_current_used(bcm); + return; + } + + /* Calculate the new attenuation values. */ + baseband_attenuation = radio->txpower[0]; + baseband_attenuation += baseband_att_delta; + radio_attenuation = radio->txpower[1]; + radio_attenuation += radio_att_delta; + + /* Get baseband and radio attenuation values into their permitted ranges. + * baseband 0-11, radio 0-9. + * Radio attenuation affects power level 4 times as much as baseband. + */ + if (radio_attenuation < 0) { + baseband_attenuation -= (4 * -radio_attenuation); + radio_attenuation = 0; + } else if (radio_attenuation > 9) { + baseband_attenuation += (4 * (radio_attenuation - 9)); + radio_attenuation = 9; + } else { + while (baseband_attenuation < 0 && radio_attenuation > 0) { + baseband_attenuation += 4; + radio_attenuation--; + } + while (baseband_attenuation > 11 && radio_attenuation < 9) { + baseband_attenuation -= 4; + radio_attenuation++; + } + } + baseband_attenuation = limit_value(baseband_attenuation, 0, 11); + + txpower = radio->txpower[2]; + if ((radio->version == 0x2050) && (radio->revision == 2)) { + if (radio_attenuation <= 1) { + if (txpower == 0) { + txpower = 3; + radio_attenuation += 2; + baseband_attenuation += 2; + } else if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { + baseband_attenuation += 4 * (radio_attenuation - 2); + radio_attenuation = 2; + } + } else if (radio_attenuation > 4 && txpower != 0) { + txpower = 0; + if (baseband_attenuation < 3) { + radio_attenuation -= 3; + baseband_attenuation += 2; + } else { + radio_attenuation -= 2; + baseband_attenuation -= 2; + } + } + } + radio->txpower[2] = txpower; + baseband_attenuation = limit_value(baseband_attenuation, 0, 11); + radio_attenuation = limit_value(radio_attenuation, 0, 9); + + bcm43xx_phy_lock(bcm, phylock_flags); + bcm43xx_radio_lock(bcm); + bcm43xx_radio_set_txpower_bg(bcm, baseband_attenuation, + radio_attenuation, txpower); + bcm43xx_phy_lo_mark_current_used(bcm); + bcm43xx_radio_unlock(bcm); + bcm43xx_phy_unlock(bcm, phylock_flags); + break; + } + default: + assert(0); + } +} + +static inline +s32 bcm43xx_tssi2dbm_ad(s32 num, s32 den) +{ + if (num < 0) + return num/den; + else + return (num+den/2)/den; +} + +static inline +s8 bcm43xx_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2) +{ + s32 m1, m2, f = 256, q, delta; + s8 i = 0; + + m1 = bcm43xx_tssi2dbm_ad(16 * pab0 + index * pab1, 32); + m2 = max(bcm43xx_tssi2dbm_ad(32768 + index * pab2, 256), 1); + do { + if (i > 15) + return -EINVAL; + q = bcm43xx_tssi2dbm_ad(f * 4096 - + bcm43xx_tssi2dbm_ad(m2 * f, 16) * f, 2048); + delta = abs(q - f); + f = q; + i++; + } while (delta >= 2); + entry[index] = limit_value(bcm43xx_tssi2dbm_ad(m1 * f, 8192), -127, 128); + return 0; +} + +/* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ +int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + s16 pab0, pab1, pab2; + u8 idx; + s8 *dyn_tssi2dbm; + + if (phy->type == BCM43xx_PHYTYPE_A) { + pab0 = (s16)(bcm->sprom.pa1b0); + pab1 = (s16)(bcm->sprom.pa1b1); + pab2 = (s16)(bcm->sprom.pa1b2); + } else { + pab0 = (s16)(bcm->sprom.pa0b0); + pab1 = (s16)(bcm->sprom.pa0b1); + pab2 = (s16)(bcm->sprom.pa0b2); + } + + if ((bcm->chip_id == 0x4301) && (radio->version != 0x2050)) { + phy->idle_tssi = 0x34; + phy->tssi2dbm = bcm43xx_tssi2dbm_b_table; + return 0; + } + + if (pab0 != 0 && pab1 != 0 && pab2 != 0 && + pab0 != -1 && pab1 != -1 && pab2 != -1) { + /* The pabX values are set in SPROM. Use them. */ + if (phy->type == BCM43xx_PHYTYPE_A) { + if ((s8)bcm->sprom.idle_tssi_tgt_aphy != 0 && + (s8)bcm->sprom.idle_tssi_tgt_aphy != -1) + phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_aphy); + else + phy->idle_tssi = 62; + } else { + if ((s8)bcm->sprom.idle_tssi_tgt_bgphy != 0 && + (s8)bcm->sprom.idle_tssi_tgt_bgphy != -1) + phy->idle_tssi = (s8)(bcm->sprom.idle_tssi_tgt_bgphy); + else + phy->idle_tssi = 62; + } + dyn_tssi2dbm = kmalloc(64, GFP_KERNEL); + if (dyn_tssi2dbm == NULL) { + printk(KERN_ERR PFX "Could not allocate memory" + "for tssi2dbm table\n"); + return -ENOMEM; + } + for (idx = 0; idx < 64; idx++) + if (bcm43xx_tssi2dbm_entry(dyn_tssi2dbm, idx, pab0, pab1, pab2)) { + phy->tssi2dbm = NULL; + printk(KERN_ERR PFX "Could not generate " + "tssi2dBm table\n"); + return -ENODEV; + } + phy->tssi2dbm = dyn_tssi2dbm; + phy->dyn_tssi_tbl = 1; + } else { + /* pabX values not set in SPROM. */ + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + /* APHY needs a generated table. */ + phy->tssi2dbm = NULL; + printk(KERN_ERR PFX "Could not generate tssi2dBm " + "table (wrong SPROM info)!\n"); + return -ENODEV; + case BCM43xx_PHYTYPE_B: + phy->idle_tssi = 0x34; + phy->tssi2dbm = bcm43xx_tssi2dbm_b_table; + break; + case BCM43xx_PHYTYPE_G: + phy->idle_tssi = 0x34; + phy->tssi2dbm = bcm43xx_tssi2dbm_g_table; + break; + } + } + + return 0; +} + +int bcm43xx_phy_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + int err = -ENODEV; + unsigned long flags; + + /* We do not want to be preempted while calibrating + * the hardware. + */ + local_irq_save(flags); + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + if (phy->rev == 2 || phy->rev == 3) { + bcm43xx_phy_inita(bcm); + err = 0; + } + break; + case BCM43xx_PHYTYPE_B: + switch (phy->rev) { + case 2: + bcm43xx_phy_initb2(bcm); + err = 0; + break; + case 4: + bcm43xx_phy_initb4(bcm); + err = 0; + break; + case 5: + bcm43xx_phy_initb5(bcm); + err = 0; + break; + case 6: + bcm43xx_phy_initb6(bcm); + err = 0; + break; + } + break; + case BCM43xx_PHYTYPE_G: + bcm43xx_phy_initg(bcm); + err = 0; + break; + } + local_irq_restore(flags); + if (err) + printk(KERN_WARNING PFX "Unknown PHYTYPE found!\n"); + + return err; +} + +void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 antennadiv; + u16 offset; + u16 value; + u32 ucodeflags; + + antennadiv = phy->antenna_diversity; + + if (antennadiv == 0xFFFF) + antennadiv = 3; + assert(antennadiv <= 3); + + ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + ucodeflags & ~BCM43xx_UCODEFLAG_AUTODIV); + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + case BCM43xx_PHYTYPE_G: + if (phy->type == BCM43xx_PHYTYPE_A) + offset = 0x0000; + else + offset = 0x0400; + + if (antennadiv == 2) + value = (3/*automatic*/ << 7); + else + value = (antennadiv << 7); + bcm43xx_phy_write(bcm, offset + 1, + (bcm43xx_phy_read(bcm, offset + 1) + & 0x7E7F) | value); + + if (antennadiv >= 2) { + if (antennadiv == 2) + value = (antennadiv << 7); + else + value = (0/*force0*/ << 7); + bcm43xx_phy_write(bcm, offset + 0x2B, + (bcm43xx_phy_read(bcm, offset + 0x2B) + & 0xFEFF) | value); + } + + if (phy->type == BCM43xx_PHYTYPE_G) { + if (antennadiv >= 2) + bcm43xx_phy_write(bcm, 0x048C, + bcm43xx_phy_read(bcm, 0x048C) + | 0x2000); + else + bcm43xx_phy_write(bcm, 0x048C, + bcm43xx_phy_read(bcm, 0x048C) + & ~0x2000); + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0461, + bcm43xx_phy_read(bcm, 0x0461) + | 0x0010); + bcm43xx_phy_write(bcm, 0x04AD, + (bcm43xx_phy_read(bcm, 0x04AD) + & 0x00FF) | 0x0015); + if (phy->rev == 2) + bcm43xx_phy_write(bcm, 0x0427, 0x0008); + else + bcm43xx_phy_write(bcm, 0x0427, + (bcm43xx_phy_read(bcm, 0x0427) + & 0x00FF) | 0x0008); + } + else if (phy->rev >= 6) + bcm43xx_phy_write(bcm, 0x049B, 0x00DC); + } else { + if (phy->rev < 3) + bcm43xx_phy_write(bcm, 0x002B, + (bcm43xx_phy_read(bcm, 0x002B) + & 0x00FF) | 0x0024); + else { + bcm43xx_phy_write(bcm, 0x0061, + bcm43xx_phy_read(bcm, 0x0061) + | 0x0010); + if (phy->rev == 3) { + bcm43xx_phy_write(bcm, 0x0093, 0x001D); + bcm43xx_phy_write(bcm, 0x0027, 0x0008); + } else { + bcm43xx_phy_write(bcm, 0x0093, 0x003A); + bcm43xx_phy_write(bcm, 0x0027, + (bcm43xx_phy_read(bcm, 0x0027) + & 0x00FF) | 0x0008); + } + } + } + break; + case BCM43xx_PHYTYPE_B: + if (bcm->current_core->rev == 2) + value = (3/*automatic*/ << 7); + else + value = (antennadiv << 7); + bcm43xx_phy_write(bcm, 0x03E2, + (bcm43xx_phy_read(bcm, 0x03E2) + & 0xFE7F) | value); + break; + default: + assert(0); + } + + if (antennadiv >= 2) { + ucodeflags = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET); + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + ucodeflags | BCM43xx_UCODEFLAG_AUTODIV); + } + + phy->antenna_diversity = antennadiv; +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h new file mode 100644 index 00000000000..1f321ef42be --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h @@ -0,0 +1,74 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_PHY_H_ +#define BCM43xx_PHY_H_ + +#include + +struct bcm43xx_private; + +void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm); +#define bcm43xx_phy_lock(bcm, flags) \ + do { \ + local_irq_save(flags); \ + bcm43xx_raw_phy_lock(bcm); \ + } while (0) +void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm); +#define bcm43xx_phy_unlock(bcm, flags) \ + do { \ + bcm43xx_raw_phy_unlock(bcm); \ + local_irq_restore(flags); \ + } while (0) + +u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset); +void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val); + +int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm); +int bcm43xx_phy_init(struct bcm43xx_private *bcm); + +void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm); +void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm); +int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect); + +void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm); +void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm); +void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm); + +/* Adjust the LocalOscillator to the saved values. + * "fixed" is only set to 1 once in initialization. Set to 0 otherwise. + */ +void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed); +void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm); + +void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, + u16 baseband_attenuation); + +#endif /* BCM43xx_PHY_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c new file mode 100644 index 00000000000..9a55e9d0052 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -0,0 +1,592 @@ +/* + + Broadcom BCM43xx wireless driver + + PIO Transmission + + Copyright (c) 2005 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx.h" +#include "bcm43xx_pio.h" +#include "bcm43xx_main.h" + +#include + + +static inline +u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue, + u16 offset) +{ + return bcm43xx_read16(queue->bcm, queue->mmio_base + offset); +} + +static inline +void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue, + u16 offset, u16 value) +{ + bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value); +} + +static inline +void tx_start(struct bcm43xx_pioqueue *queue) +{ + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_INIT); +} + +static inline +void tx_octet(struct bcm43xx_pioqueue *queue, + u8 octet) +{ + if (queue->bcm->current_core->rev < 3) { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI); + } else { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet); + } +} + +static inline +void tx_data(struct bcm43xx_pioqueue *queue, + u8 *packet, + unsigned int octets) +{ + u16 data; + unsigned int i = 0; + + if (queue->bcm->current_core->rev < 3) { + data = be16_to_cpu( *((u16 *)packet) ); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); + i += 2; + } + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_WRITELO | BCM43xx_PIO_TXCTL_WRITEHI); + for ( ; i < octets - 1; i += 2) { + data = be16_to_cpu( *((u16 *)(packet + i)) ); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); + } + if (octets % 2) + tx_octet(queue, packet[octets - 1]); +} + +static inline +void tx_complete(struct bcm43xx_pioqueue *queue, + struct sk_buff *skb) +{ + u16 data; + + if (queue->bcm->current_core->rev < 3) { + data = be16_to_cpu( *((u16 *)(skb->data + skb->len - 2)) ); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_WRITEHI | BCM43xx_PIO_TXCTL_COMPLETE); + } else { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_COMPLETE); + } +} + +static inline +u16 generate_cookie(struct bcm43xx_pioqueue *queue, + int packetindex) +{ + u16 cookie = 0x0000; + + /* We use the upper 4 bits for the PIO + * controller ID and the lower 12 bits + * for the packet index (in the cache). + */ + switch (queue->mmio_base) { + default: + assert(0); + case BCM43xx_MMIO_PIO1_BASE: + break; + case BCM43xx_MMIO_PIO2_BASE: + cookie = 0x1000; + break; + case BCM43xx_MMIO_PIO3_BASE: + cookie = 0x2000; + break; + case BCM43xx_MMIO_PIO4_BASE: + cookie = 0x3000; + break; + } + assert(((u16)packetindex & 0xF000) == 0x0000); + cookie |= (u16)packetindex; + + return cookie; +} + +static inline +struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm, + u16 cookie, + struct bcm43xx_pio_txpacket **packet) +{ + struct bcm43xx_pioqueue *queue = NULL; + int packetindex; + + switch (cookie & 0xF000) { + case 0x0000: + queue = bcm->current_core->pio->queue0; + break; + case 0x1000: + queue = bcm->current_core->pio->queue1; + break; + case 0x2000: + queue = bcm->current_core->pio->queue2; + break; + case 0x3000: + queue = bcm->current_core->pio->queue3; + break; + default: + assert(0); + } + + packetindex = (cookie & 0x0FFF); + assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS); + *packet = queue->__tx_packets_cache + packetindex; + + return queue; +} + +static inline +void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue, + struct sk_buff *skb, + struct bcm43xx_pio_txpacket *packet) +{ + unsigned int octets; + + assert(skb_shinfo(skb)->nr_frags == 0); + assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); + + __skb_push(skb, sizeof(struct bcm43xx_txhdr)); + bcm43xx_generate_txhdr(queue->bcm, + (struct bcm43xx_txhdr *)skb->data, + skb->data + sizeof(struct bcm43xx_txhdr), + skb->len - sizeof(struct bcm43xx_txhdr), + (packet->xmitted_frags == 0), + generate_cookie(queue, pio_txpacket_getindex(packet))); + + tx_start(queue); + octets = skb->len; + if (queue->bcm->current_core->rev < 3) //FIXME: && this is the last packet in the queue. + octets -= 2; + tx_data(queue, (u8 *)skb->data, octets); + tx_complete(queue, skb); +} + +static inline +int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) +{ + struct bcm43xx_pioqueue *queue = packet->queue; + struct ieee80211_txb *txb = packet->txb; + struct sk_buff *skb; + u16 octets; + int i; + + for (i = packet->xmitted_frags; i < txb->nr_frags; i++) { + skb = txb->fragments[i]; + + octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr); + + assert(queue->tx_devq_size >= octets); + assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS); + assert(queue->tx_devq_used <= queue->tx_devq_size); + /* Check if there is sufficient free space on the device + * TX queue. If not, return and let the TX-work-handler + * retry later. + */ + if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS) + return -EBUSY; + if (queue->tx_devq_used + octets > queue->tx_devq_size) + return -EBUSY; + /* Now poke the device. */ + pio_tx_write_fragment(queue, skb, packet); + + /* Account for the packet size. + * (We must not overflow the device TX queue) + */ + queue->tx_devq_packets++; + queue->tx_devq_used += octets; + + assert(packet->xmitted_frags <= packet->txb->nr_frags); + packet->xmitted_frags++; + packet->xmitted_octets += octets; + } + list_move_tail(&packet->list, &queue->txrunning); + + return 0; +} + +static void free_txpacket(struct bcm43xx_pio_txpacket *packet) +{ + struct bcm43xx_pioqueue *queue = packet->queue; + + ieee80211_txb_free(packet->txb); + + list_move(&packet->list, &packet->queue->txfree); + + assert(queue->tx_devq_used >= packet->xmitted_octets); + queue->tx_devq_used -= packet->xmitted_octets; + assert(queue->tx_devq_packets >= packet->xmitted_frags); + queue->tx_devq_packets -= packet->xmitted_frags; +} + +static void txwork_handler(void *d) +{ + struct bcm43xx_pioqueue *queue = d; + unsigned long flags; + struct bcm43xx_pio_txpacket *packet, *tmp_packet; + int err; + + spin_lock_irqsave(&queue->txlock, flags); + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { + assert(packet->xmitted_frags < packet->txb->nr_frags); + if (packet->xmitted_frags == 0) { + int i; + struct sk_buff *skb; + + /* Check if the device queue is big + * enough for every fragment. If not, drop the + * whole packet. + */ + for (i = 0; i < packet->txb->nr_frags; i++) { + skb = packet->txb->fragments[i]; + if (unlikely(skb->len > queue->tx_devq_size)) { + dprintkl(KERN_ERR PFX "PIO TX device queue too small. " + "Dropping packet...\n"); + free_txpacket(packet); + goto next_packet; + } + } + } + /* Now try to transmit the packet. + * This may not completely succeed. + */ + err = pio_tx_packet(packet); + if (err) + break; +next_packet: + continue; + } + spin_unlock_irqrestore(&queue->txlock, flags); +} + +static void setup_txqueues(struct bcm43xx_pioqueue *queue) +{ + struct bcm43xx_pio_txpacket *packet; + int i; + + for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) { + packet = queue->__tx_packets_cache + i; + + packet->queue = queue; + INIT_LIST_HEAD(&packet->list); + + list_add(&packet->list, &queue->txfree); + } +} + +static +struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm, + u16 pio_mmio_base) +{ + struct bcm43xx_pioqueue *queue; + u32 value; + u16 qsize; + + queue = kmalloc(sizeof(*queue), GFP_KERNEL); + if (!queue) + goto out; + memset(queue, 0, sizeof(*queue)); + + queue->bcm = bcm; + queue->mmio_base = pio_mmio_base; + + INIT_LIST_HEAD(&queue->txfree); + INIT_LIST_HEAD(&queue->txqueue); + INIT_LIST_HEAD(&queue->txrunning); + spin_lock_init(&queue->txlock); + INIT_WORK(&queue->txwork, txwork_handler, queue); + + value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + value |= BCM43xx_SBF_XFER_REG_BYTESWAP; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value); + + qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE); + if (qsize <= BCM43xx_PIO_TXQADJUST) { + printk(KERN_ERR PFX "PIO tx queue too small (%u)\n", qsize); + goto err_freequeue; + } + qsize -= BCM43xx_PIO_TXQADJUST; + queue->tx_devq_size = qsize; + + setup_txqueues(queue); + +out: + return queue; + +err_freequeue: + kfree(queue); + queue = NULL; + goto out; +} + +static void cancel_transfers(struct bcm43xx_pioqueue *queue) +{ + struct bcm43xx_pio_txpacket *packet, *tmp_packet; + + netif_tx_disable(queue->bcm->net_dev); + assert(queue->bcm->shutting_down); + cancel_delayed_work(&queue->txwork); + flush_workqueue(queue->bcm->workqueue); + + list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) + free_txpacket(packet); + list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) + free_txpacket(packet); +} + +static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) +{ + if (!queue) + return; + + cancel_transfers(queue); + kfree(queue); +} + +void bcm43xx_pio_free(struct bcm43xx_private *bcm) +{ + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue3); + bcm->current_core->pio->queue3 = NULL; + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2); + bcm->current_core->pio->queue2 = NULL; + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1); + bcm->current_core->pio->queue1 = NULL; + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0); + bcm->current_core->pio->queue0 = NULL; +} + +int bcm43xx_pio_init(struct bcm43xx_private *bcm) +{ + struct bcm43xx_pioqueue *queue; + int err = -ENOMEM; + + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE); + if (!queue) + goto out; + bcm->current_core->pio->queue0 = queue; + + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE); + if (!queue) + goto err_destroy0; + bcm->current_core->pio->queue1 = queue; + + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE); + if (!queue) + goto err_destroy1; + bcm->current_core->pio->queue2 = queue; + + queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE); + if (!queue) + goto err_destroy2; + bcm->current_core->pio->queue3 = queue; + + if (bcm->current_core->rev < 3) + bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND; + + dprintk(KERN_INFO PFX "PIO initialized\n"); + err = 0; +out: + return err; + +err_destroy2: + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2); + bcm->current_core->pio->queue2 = NULL; +err_destroy1: + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1); + bcm->current_core->pio->queue1 = NULL; +err_destroy0: + bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0); + bcm->current_core->pio->queue0 = NULL; + goto out; +} + +static inline +int pio_transfer_txb(struct bcm43xx_pioqueue *queue, + struct ieee80211_txb *txb) +{ + struct bcm43xx_pio_txpacket *packet; + unsigned long flags; + u16 tmp; + + spin_lock_irqsave(&queue->txlock, flags); + assert(!queue->tx_suspended); + assert(!list_empty(&queue->txfree)); + + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); + if (tmp & BCM43xx_PIO_TXCTL_SUSPEND) { + spin_unlock_irqrestore(&queue->txlock, flags); + return -EBUSY; + } + + packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list); + + packet->txb = txb; + list_move_tail(&packet->list, &queue->txqueue); + packet->xmitted_octets = 0; + packet->xmitted_frags = 0; + + /* Suspend TX, if we are out of packets in the "free" queue. */ + if (unlikely(list_empty(&queue->txfree))) { + netif_stop_queue(queue->bcm->net_dev); + queue->tx_suspended = 1; + } + + spin_unlock_irqrestore(&queue->txlock, flags); + queue_work(queue->bcm->workqueue, &queue->txwork); + + return 0; +} + +int fastcall bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + return pio_transfer_txb(bcm->current_core->pio->queue1, txb); +} + +void fastcall +bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ + struct bcm43xx_pioqueue *queue; + struct bcm43xx_pio_txpacket *packet; + unsigned long flags; + + queue = parse_cookie(bcm, status->cookie, &packet); + assert(queue); + spin_lock_irqsave(&queue->txlock, flags); + free_txpacket(packet); + if (unlikely(queue->tx_suspended)) { + queue->tx_suspended = 0; + netif_wake_queue(queue->bcm->net_dev); + } + + /* If there are packets on the txqueue, + * start the work handler again. + */ + if (!list_empty(&queue->txqueue)) { + queue_work(queue->bcm->workqueue, + &queue->txwork); + } + spin_unlock_irqrestore(&queue->txlock, flags); +} + +static void pio_rx_error(struct bcm43xx_pioqueue *queue, + const char *error) +{ + printk("PIO RX error: %s\n", error); + bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_READY); +} + +void fastcall +bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) +{ + u16 preamble[21] = { 0 }; + struct bcm43xx_rxhdr *rxhdr; + u16 tmp; + u16 len; + int i, err; + int preamble_readwords; + struct sk_buff *skb; + + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); + if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) { + dprintkl(KERN_ERR PFX "PIO RX: No data available\n"); + return; + } + bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_DATAAVAILABLE); + + for (i = 0; i < 10; i++) { + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); + if (tmp & BCM43xx_PIO_RXCTL_READY) + goto data_ready; + udelay(10); + } + dprintkl(KERN_ERR PFX "PIO RX timed out\n"); + return; +data_ready: + + len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); + if (unlikely(len > 0x700)) { + pio_rx_error(queue, "len > 0x700"); + return; + } + if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) { + pio_rx_error(queue, "len == 0"); + return; + } + preamble[0] = cpu_to_le16(len); + if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) + preamble_readwords = 14 / sizeof(u16); + else + preamble_readwords = 18 / sizeof(u16); + for (i = 0; i < preamble_readwords; i++) { + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); + preamble[i + 1] = cpu_to_be16(tmp); + } + rxhdr = (struct bcm43xx_rxhdr *)preamble; + if (unlikely(rxhdr->flags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) { + pio_rx_error(queue, "invalid frame"); + if (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE) { + for (i = 0; i < 15; i++) + bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); /* dummy read. */ + } + return; + } +//FIXME +#if 0 + if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) { + bcm43xx_rx_transmitstatus(queue->bcm, + (const struct bcm43xx_hwxmitstatus *)(preamble + 1)); + return; + } +#endif + skb = dev_alloc_skb(len); + if (unlikely(!skb)) { + pio_rx_error(queue, "out of memory"); + return; + } + skb_put(skb, len); + for (i = 0; i < len - 1; i += 2) { + tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); + *((u16 *)(skb->data + i)) = tmp; + } + if (len % 2) { + tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); + skb->data[len - 1] = (tmp & 0x00FF); + skb->data[0] = (tmp & 0xFF00) >> 8; + } + err = bcm43xx_rx(queue->bcm, skb, rxhdr); + if (unlikely(err)) + dev_kfree_skb_irq(skb); +} + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h new file mode 100644 index 00000000000..71b92ee3416 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h @@ -0,0 +1,88 @@ +#ifndef BCM43xx_PIO_H_ +#define BCM43xx_PIO_H_ + +#include "bcm43xx.h" + +#include +#include +#include +#include + + +#define BCM43xx_PIO_TXCTL 0x00 +#define BCM43xx_PIO_TXDATA 0x02 +#define BCM43xx_PIO_TXQBUFSIZE 0x04 +#define BCM43xx_PIO_RXCTL 0x08 +#define BCM43xx_PIO_RXDATA 0x0A + +#define BCM43xx_PIO_TXCTL_WRITEHI (1 << 0) +#define BCM43xx_PIO_TXCTL_WRITELO (1 << 1) +#define BCM43xx_PIO_TXCTL_COMPLETE (1 << 2) +#define BCM43xx_PIO_TXCTL_INIT (1 << 3) +#define BCM43xx_PIO_TXCTL_SUSPEND (1 << 7) + +#define BCM43xx_PIO_RXCTL_DATAAVAILABLE (1 << 0) +#define BCM43xx_PIO_RXCTL_READY (1 << 1) + +/* PIO constants */ +#define BCM43xx_PIO_MAXTXDEVQPACKETS 31 +#define BCM43xx_PIO_TXQADJUST 80 + +/* PIO tuning knobs */ +#define BCM43xx_PIO_MAXTXPACKETS 256 + + +struct bcm43xx_pioqueue; +struct bcm43xx_xmitstatus; + +struct bcm43xx_pio_txpacket { + struct bcm43xx_pioqueue *queue; + struct ieee80211_txb *txb; + struct list_head list; + + u8 xmitted_frags; + u16 xmitted_octets; +}; + +#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->__tx_packets_cache)) + +struct bcm43xx_pioqueue { + struct bcm43xx_private *bcm; + u16 mmio_base; + + u8 tx_suspended:1; + + /* Adjusted size of the device internal TX buffer. */ + u16 tx_devq_size; + /* Used octets of the device internal TX buffer. */ + u16 tx_devq_used; + /* Used packet slots in the device internal TX buffer. */ + u8 tx_devq_packets; + /* Packets from the txfree list can + * be taken on incoming TX requests. + */ + struct list_head txfree; + /* Packets on the txqueue are queued, + * but not completely written to the chip, yet. + */ + struct list_head txqueue; + /* Packets on the txrunning queue are completely + * posted to the device. We are waiting for the txstatus. + */ + struct list_head txrunning; + /* Locking of the TX queues and the accounting. */ + spinlock_t txlock; + struct work_struct txwork; + struct bcm43xx_pio_txpacket __tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS]; +}; + +int bcm43xx_pio_init(struct bcm43xx_private *bcm); +void bcm43xx_pio_free(struct bcm43xx_private *bcm); + +int FASTCALL(bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb)); +void FASTCALL(bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status)); + +void FASTCALL(bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)); +#endif /* BCM43xx_PIO_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.c b/drivers/net/wireless/bcm43xx/bcm43xx_power.c new file mode 100644 index 00000000000..3c92b62807c --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.c @@ -0,0 +1,358 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include + +#include "bcm43xx.h" +#include "bcm43xx_power.h" +#include "bcm43xx_main.h" + + +/* Get max/min slowclock frequency + * as described in http://bcm-specs.sipsolutions.net/PowerControl + */ +static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, + int get_max) +{ + int limit = 0; + int divisor; + int selection; + int err; + u32 tmp; + struct bcm43xx_coreinfo *old_core; + + if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) + goto out; + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err) + goto out; + + if (bcm->current_core->rev < 6) { + if ((bcm->bustype == BCM43xx_BUSTYPE_PCMCIA) || + (bcm->bustype == BCM43xx_BUSTYPE_SB)) { + selection = 1; + divisor = 32; + } else { + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp); + if (err) { + printk(KERN_ERR PFX "clockfreqlimit pcicfg read failure\n"); + goto out_switchback; + } + if (tmp & 0x10) { + /* PCI */ + selection = 2; + divisor = 64; + } else { + /* XTAL */ + selection = 1; + divisor = 32; + } + } + } else if (bcm->current_core->rev < 10) { + selection = (tmp & 0x07); + if (selection) { + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); + divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); + } else + divisor = 1; + } else { + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL); + divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); + selection = 1; + } + + switch (selection) { + case 0: + /* LPO */ + if (get_max) + limit = 43000; + else + limit = 25000; + break; + case 1: + /* XTAL */ + if (get_max) + limit = 20200000; + else + limit = 19800000; + break; + case 2: + /* PCI */ + if (get_max) + limit = 34000000; + else + limit = 25000000; + break; + default: + assert(0); + } + limit /= divisor; + +out_switchback: + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + +out: + return limit; +} + +/* init power control + * as described in http://bcm-specs.sipsolutions.net/PowerControl + */ +int bcm43xx_pctl_init(struct bcm43xx_private *bcm) +{ + int err, maxfreq; + struct bcm43xx_coreinfo *old_core; + + if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) + return 0; + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err == -ENODEV) + return 0; + if (err) + goto out; + + maxfreq = bcm43xx_pctl_clockfreqlimit(bcm, 1); + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY, + (maxfreq * 150 + 999999) / 1000000); + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_FREFSELDELAY, + (maxfreq * 15 + 999999) / 1000000); + + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + +out: + return err; +} + +u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm) +{ + u16 delay = 0; + int err; + u32 pll_on_delay; + struct bcm43xx_coreinfo *old_core; + int minfreq; + + if (bcm->bustype != BCM43xx_BUSTYPE_PCI) + goto out; + if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) + goto out; + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err == -ENODEV) + goto out; + + minfreq = bcm43xx_pctl_clockfreqlimit(bcm, 0); + pll_on_delay = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_PLLONDELAY); + delay = (((pll_on_delay + 2) * 1000000) + (minfreq - 1)) / minfreq; + + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + +out: + return delay; +} + +/* set the powercontrol clock + * as described in http://bcm-specs.sipsolutions.net/PowerControl + */ +int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode) +{ + int err; + struct bcm43xx_coreinfo *old_core; + u32 tmp; + + old_core = bcm->current_core; + err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + if (err == -ENODEV) + return 0; + if (err) + goto out; + + if (bcm->core_chipcommon.rev < 6) { + if (mode == BCM43xx_PCTL_CLK_FAST) { + err = bcm43xx_pctl_set_crystal(bcm, 1); + if (err) + goto out; + } + } else { + if ((bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL) && + (bcm->core_chipcommon.rev < 10)) { + switch (mode) { + case BCM43xx_PCTL_CLK_FAST: + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); + tmp = (tmp & ~BCM43xx_PCTL_FORCE_SLOW) | BCM43xx_PCTL_FORCE_PLL; + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); + break; + case BCM43xx_PCTL_CLK_SLOW: + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); + tmp |= BCM43xx_PCTL_FORCE_SLOW; + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); + break; + case BCM43xx_PCTL_CLK_DYNAMIC: + tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); + tmp &= ~BCM43xx_PCTL_FORCE_SLOW; + tmp |= BCM43xx_PCTL_FORCE_PLL; + tmp &= ~BCM43xx_PCTL_DYN_XTAL; + bcm43xx_write32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL, tmp); + } + } + } + + err = bcm43xx_switch_core(bcm, old_core); + assert(err == 0); + +out: + return err; +} + +int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on) +{ + int err; + u32 in, out, outenable; + + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_IN, &in); + if (err) + goto err_pci; + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &out); + if (err) + goto err_pci; + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUTENABLE, &outenable); + if (err) + goto err_pci; + + outenable |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN); + + if (on) { + if (in & 0x40) + return 0; + + out |= (BCM43xx_PCTL_XTAL_POWERUP | BCM43xx_PCTL_PLL_POWERDOWN); + + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); + if (err) + goto err_pci; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable); + if (err) + goto err_pci; + udelay(1000); + + out &= ~BCM43xx_PCTL_PLL_POWERDOWN; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); + if (err) + goto err_pci; + udelay(5000); + } else { + if (bcm->current_core->rev < 5) + return 0; + if (bcm->sprom.boardflags & BCM43xx_BFL_XTAL_NOSLOW) + return 0; + +/* XXX: Why BCM43xx_MMIO_RADIO_HWENABLED_xx can't be read at this time? + * err = bcm43xx_switch_core(bcm, bcm->active_80211_core); + * if (err) + * return err; + * if (((bcm->current_core->rev >= 3) && + * (bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI) & (1 << 16))) || + * ((bcm->current_core->rev < 3) && + * !(bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO) & (1 << 4)))) + * return 0; + * err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); + * if (err) + * return err; + */ + + err = bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_SLOW); + if (err) + goto out; + out &= ~BCM43xx_PCTL_XTAL_POWERUP; + out |= BCM43xx_PCTL_PLL_POWERDOWN; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUT, out); + if (err) + goto err_pci; + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCTL_OUTENABLE, outenable); + if (err) + goto err_pci; + } + +out: + return err; + +err_pci: + printk(KERN_ERR PFX "Error: pctl_set_clock() could not access PCI config space!\n"); + err = -EBUSY; + goto out; +} + +/* Set the PowerSavingControlBits. + * Bitvalues: + * 0 => unset the bit + * 1 => set the bit + * -1 => calculate the bit + */ +void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm, + int bit25, int bit26) +{ + int i; + u32 status; + +//FIXME: Force 25 to off and 26 to on for now: +bit25 = 0; +bit26 = 1; + + if (bit25 == -1) { + //TODO: If powersave is not off and FIXME is not set and we are not in adhoc + // and thus is not an AP and we are associated, set bit 25 + } + if (bit26 == -1) { + //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME, + // or we are associated, or FIXME, or the latest PS-Poll packet sent was + // successful, set bit26 + } + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + if (bit25) + status |= BCM43xx_SBF_PS1; + else + status &= ~BCM43xx_SBF_PS1; + if (bit26) + status |= BCM43xx_SBF_PS2; + else + status &= ~BCM43xx_SBF_PS2; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + if (bit26 && bcm->current_core->rev >= 5) { + for (i = 0; i < 100; i++) { + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0040) != 4) + break; + udelay(10); + } + } +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.h b/drivers/net/wireless/bcm43xx/bcm43xx_power.h new file mode 100644 index 00000000000..5f63640810b --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.h @@ -0,0 +1,47 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_POWER_H_ +#define BCM43xx_POWER_H_ + +#include + + +struct bcm43xx_private; + +int bcm43xx_pctl_init(struct bcm43xx_private *bcm); +int bcm43xx_pctl_set_clock(struct bcm43xx_private *bcm, u16 mode); +int bcm43xx_pctl_set_crystal(struct bcm43xx_private *bcm, int on); +u16 bcm43xx_pctl_powerup_delay(struct bcm43xx_private *bcm); + +void bcm43xx_power_saving_ctl_bits(struct bcm43xx_private *bcm, + int bit25, int bit26); + +#endif /* BCM43xx_POWER_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c new file mode 100644 index 00000000000..1e65658552b --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -0,0 +1,1766 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include + +#include "bcm43xx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_phy.h" +#include "bcm43xx_radio.h" +#include "bcm43xx_ilt.h" + + +/* Table for bcm43xx_radio_calibrationvalue() */ +static const u16 rcc_table[16] = { + 0x0002, 0x0003, 0x0001, 0x000F, + 0x0006, 0x0007, 0x0005, 0x000F, + 0x000A, 0x000B, 0x0009, 0x000F, + 0x000E, 0x000F, 0x000D, 0x000F, +}; + +/* Reverse the bits of a 4bit value. + * Example: 1101 is flipped 1011 + */ +static u16 flip_4bit(u16 value) +{ + u16 flipped = 0x0000; + + assert((value & ~0x000F) == 0x0000); + + flipped |= (value & 0x0001) << 3; + flipped |= (value & 0x0002) << 1; + flipped |= (value & 0x0004) >> 1; + flipped |= (value & 0x0008) >> 3; + + return flipped; +} + +/* Get the freq, as it has to be written to the device. */ +static inline +u16 channel2freq_bg(u8 channel) +{ + /* Frequencies are given as frequencies_bg[index] + 2.4GHz + * Starting with channel 1 + */ + static const u16 frequencies_bg[14] = { + 12, 17, 22, 27, + 32, 37, 42, 47, + 52, 57, 62, 67, + 72, 84, + }; + + assert(channel >= 1 && channel <= 14); + + return frequencies_bg[channel - 1]; +} + +/* Get the freq, as it has to be written to the device. */ +static inline +u16 channel2freq_a(u8 channel) +{ + assert(channel <= 200); + + return (5000 + 5 * channel); +} + +void bcm43xx_radio_lock(struct bcm43xx_private *bcm) +{ + u32 status; + + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + status |= BCM43xx_SBF_RADIOREG_LOCK; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + udelay(10); +} + +void bcm43xx_radio_unlock(struct bcm43xx_private *bcm) +{ + u32 status; + + bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_VER); /* dummy read */ + status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); + status &= ~BCM43xx_SBF_RADIOREG_LOCK; + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); +} + +u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + offset |= 0x0040; + break; + case BCM43xx_PHYTYPE_B: + if (radio->version == 0x2053) { + if (offset < 0x70) + offset += 0x80; + else if (offset < 0x80) + offset += 0x70; + } else if (radio->version == 0x2050) { + offset |= 0x80; + } else + assert(0); + break; + case BCM43xx_PHYTYPE_G: + offset |= 0x80; + break; + } + + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset); + return bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW); +} + +void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val) +{ + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset); + bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW, val); +} + +static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm, + s16 first, s16 second, s16 third) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 i; + u16 start = 0x08, end = 0x18; + u16 offset = 0x0400; + u16 tmp; + + if (phy->rev <= 1) { + offset = 0x5000; + start = 0x10; + end = 0x20; + } + + for (i = 0; i < 4; i++) + bcm43xx_ilt_write16(bcm, offset + i, first); + + for (i = start; i < end; i++) + bcm43xx_ilt_write16(bcm, offset + i, second); + + if (third != -1) { + tmp = ((u16)third << 14) | ((u16)third << 6); + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | tmp); + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | tmp); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | tmp); + } + bcm43xx_dummy_transmission(bcm); +} + +static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 i, tmp; + u16 offset = 0x0400; + u16 start = 0x0008, end = 0x0018; + + if (phy->rev <= 1) { + offset = 0x5000; + start = 0x0010; + end = 0x0020; + } + + for (i = 0; i < 4; i++) { + tmp = (i & 0xFFFC); + tmp |= (i & 0x0001) << 1; + tmp |= (i & 0x0002) >> 1; + + bcm43xx_ilt_write16(bcm, offset + i, tmp); + } + + for (i = start; i < end; i++) + bcm43xx_ilt_write16(bcm, offset + i, i - start); + + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | 0x4040); + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) & 0xBFBF) | 0x4040); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) & 0xBFBF) | 0x4000); + bcm43xx_dummy_transmission(bcm); +} + +/* Synthetic PU workaround */ +static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + + if (radio->version != 0x2050 || radio->revision >= 6) { + /* We do not need the workaround. */ + return; + } + + if (channel <= 10) { + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, + channel2freq_bg(channel + 4)); + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, + channel2freq_bg(1)); + } + udelay(100); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, + channel2freq_bg(channel)); +} + +u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u8 ret = 0; + u16 saved, rssi, temp; + int i, j = 0; + + saved = bcm43xx_phy_read(bcm, 0x0403); + bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_phy_write(bcm, 0x0403, (saved & 0xFFF8) | 5); + if (radio->aci_hw_rssi) + rssi = bcm43xx_phy_read(bcm, 0x048A) & 0x3F; + else + rssi = saved & 0x3F; + /* clamp temp to signed 5bit */ + if (rssi > 32) + rssi -= 64; + for (i = 0;i < 100; i++) { + temp = (bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x3F; + if (temp > 32) + temp -= 64; + if (temp < rssi) + j++; + if (j >= 20) + ret = 1; + } + bcm43xx_phy_write(bcm, 0x0403, saved); + + return ret; +} + +u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u8 ret[13]; + unsigned int channel = radio->channel; + unsigned int i, j, start, end; + unsigned long phylock_flags; + + if (!((phy->type == BCM43xx_PHYTYPE_G) && (phy->rev > 0))) + return 0; + + bcm43xx_phy_lock(bcm, phylock_flags); + bcm43xx_radio_lock(bcm); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF); + bcm43xx_set_all_gains(bcm, 3, 8, 1); + + start = (channel - 5 > 0) ? channel - 5 : 1; + end = (channel + 5 < 14) ? channel + 5 : 13; + + for (i = start; i <= end; i++) { + if (abs(channel - i) > 2) + ret[i-1] = bcm43xx_radio_aci_detect(bcm, i); + } + bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_phy_write(bcm, 0x0802, + (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC) | 0x0003); + bcm43xx_phy_write(bcm, 0x0403, + bcm43xx_phy_read(bcm, 0x0403) & 0xFFF8); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000); + bcm43xx_set_original_gains(bcm); + for (i = 0; i < 13; i++) { + if (!ret[i]) + continue; + end = (i + 5 < 13) ? i + 5 : 13; + for (j = i; j < end; j++) + ret[j] = 1; + } + bcm43xx_radio_unlock(bcm); + bcm43xx_phy_unlock(bcm, phylock_flags); + + return ret[channel - 1]; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val) +{ + bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset); + bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_DATA, (u16)val); +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset) +{ + u16 val; + + bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset); + val = bcm43xx_phy_read(bcm, BCM43xx_PHY_NRSSILT_DATA); + + return (s16)val; +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val) +{ + u16 i; + s16 tmp; + + for (i = 0; i < 64; i++) { + tmp = bcm43xx_nrssi_hw_read(bcm, i); + tmp -= val; + tmp = limit_value(tmp, -32, 31); + bcm43xx_nrssi_hw_write(bcm, i, tmp); + } +} + +/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ +void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm) +{ + s16 i, delta; + s32 tmp; + + delta = 0x1F - bcm->current_core->radio->nrssi[0]; + for (i = 0; i < 64; i++) { + tmp = (i - delta) * bcm->current_core->radio->nrssislope; + tmp /= 0x10000; + tmp += 0x3A; + tmp = limit_value(tmp, 0, 0x3F); + bcm->current_core->radio->nrssi_lt[i] = tmp; + } +} + +static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + u16 backup[20] = { 0 }; + s16 v47F; + u16 i; + u16 saved = 0xFFFF; + + backup[0] = bcm43xx_phy_read(bcm, 0x0001); + backup[1] = bcm43xx_phy_read(bcm, 0x0811); + backup[2] = bcm43xx_phy_read(bcm, 0x0812); + backup[3] = bcm43xx_phy_read(bcm, 0x0814); + backup[4] = bcm43xx_phy_read(bcm, 0x0815); + backup[5] = bcm43xx_phy_read(bcm, 0x005A); + backup[6] = bcm43xx_phy_read(bcm, 0x0059); + backup[7] = bcm43xx_phy_read(bcm, 0x0058); + backup[8] = bcm43xx_phy_read(bcm, 0x000A); + backup[9] = bcm43xx_phy_read(bcm, 0x0003); + backup[10] = bcm43xx_radio_read16(bcm, 0x007A); + backup[11] = bcm43xx_radio_read16(bcm, 0x0043); + + bcm43xx_phy_write(bcm, 0x0429, + bcm43xx_phy_read(bcm, 0x0429) & 0x7FFF); + bcm43xx_phy_write(bcm, 0x0001, + (bcm43xx_phy_read(bcm, 0x0001) & 0x3FFF) | 0x4000); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x000C); + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) & 0xFFF3) | 0x0004); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) & ~(0x1 | 0x2)); + if (phy->rev >= 6) { + backup[12] = bcm43xx_phy_read(bcm, 0x002E); + backup[13] = bcm43xx_phy_read(bcm, 0x002F); + backup[14] = bcm43xx_phy_read(bcm, 0x080F); + backup[15] = bcm43xx_phy_read(bcm, 0x0810); + backup[16] = bcm43xx_phy_read(bcm, 0x0801); + backup[17] = bcm43xx_phy_read(bcm, 0x0060); + backup[18] = bcm43xx_phy_read(bcm, 0x0014); + backup[19] = bcm43xx_phy_read(bcm, 0x0478); + + bcm43xx_phy_write(bcm, 0x002E, 0); + bcm43xx_phy_write(bcm, 0x002F, 0); + bcm43xx_phy_write(bcm, 0x080F, 0); + bcm43xx_phy_write(bcm, 0x0810, 0); + bcm43xx_phy_write(bcm, 0x0478, + bcm43xx_phy_read(bcm, 0x0478) | 0x0100); + bcm43xx_phy_write(bcm, 0x0801, + bcm43xx_phy_read(bcm, 0x0801) | 0x0040); + bcm43xx_phy_write(bcm, 0x0060, + bcm43xx_phy_read(bcm, 0x0060) | 0x0040); + bcm43xx_phy_write(bcm, 0x0014, + bcm43xx_phy_read(bcm, 0x0014) | 0x0200); + } + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0070); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); + udelay(30); + + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == 31) { + for (i = 7; i >= 4; i--) { + bcm43xx_radio_write16(bcm, 0x007B, i); + udelay(20); + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F < 31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 4; + } else { + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0001); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x000C); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) | 0x000C); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x0030); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) | 0x0030); + bcm43xx_phy_write(bcm, 0x005A, 0x0480); + bcm43xx_phy_write(bcm, 0x0059, 0x0810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->rev == 0) { + bcm43xx_phy_write(bcm, 0x0003, 0x0122); + } else { + bcm43xx_phy_write(bcm, 0x000A, + bcm43xx_phy_read(bcm, 0x000A) + | 0x2000); + } + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0004); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB); + bcm43xx_phy_write(bcm, 0x0003, + (bcm43xx_phy_read(bcm, 0x0003) & 0xFF9F) + | 0x0040); + bcm43xx_phy_write(bcm, 0x007A, + bcm43xx_phy_read(bcm, 0x007A) | 0x000F); + bcm43xx_set_all_gains(bcm, 3, 0, 1); + bcm43xx_radio_write16(bcm, 0x0043, + (bcm43xx_radio_read16(bcm, 0x0043) + & 0x00F0) | 0x000F); + udelay(30); + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F == -32) { + for (i = 0; i < 4; i++) { + bcm43xx_radio_write16(bcm, 0x007B, i); + udelay(20); + v47F = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (v47F >= 0x20) + v47F -= 0x40; + if (v47F > -31 && saved == 0xFFFF) + saved = i; + } + if (saved == 0xFFFF) + saved = 3; + } else + saved = 0; + } + bcm43xx_radio_write16(bcm, 0x007B, saved); + + if (phy->rev >= 6) { + bcm43xx_phy_write(bcm, 0x002E, backup[12]); + bcm43xx_phy_write(bcm, 0x002F, backup[13]); + bcm43xx_phy_write(bcm, 0x080F, backup[14]); + bcm43xx_phy_write(bcm, 0x0810, backup[15]); + } + bcm43xx_phy_write(bcm, 0x0814, backup[3]); + bcm43xx_phy_write(bcm, 0x0815, backup[4]); + bcm43xx_phy_write(bcm, 0x005A, backup[5]); + bcm43xx_phy_write(bcm, 0x0059, backup[6]); + bcm43xx_phy_write(bcm, 0x0058, backup[7]); + bcm43xx_phy_write(bcm, 0x000A, backup[8]); + bcm43xx_phy_write(bcm, 0x0003, backup[9]); + bcm43xx_radio_write16(bcm, 0x0043, backup[11]); + bcm43xx_radio_write16(bcm, 0x007A, backup[10]); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) | 0x1 | 0x2); + bcm43xx_phy_write(bcm, 0x0429, + bcm43xx_phy_read(bcm, 0x0429) | 0x8000); + bcm43xx_set_original_gains(bcm); + if (phy->rev >= 6) { + bcm43xx_phy_write(bcm, 0x0801, backup[16]); + bcm43xx_phy_write(bcm, 0x0060, backup[17]); + bcm43xx_phy_write(bcm, 0x0014, backup[18]); + bcm43xx_phy_write(bcm, 0x0478, backup[19]); + } + bcm43xx_phy_write(bcm, 0x0001, backup[0]); + bcm43xx_phy_write(bcm, 0x0812, backup[2]); + bcm43xx_phy_write(bcm, 0x0811, backup[1]); +} + +void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 backup[18] = { 0 }; + u16 tmp; + s16 nrssi0, nrssi1; + + switch (phy->type) { + case BCM43xx_PHYTYPE_B: + backup[0] = bcm43xx_radio_read16(bcm, 0x007A); + backup[1] = bcm43xx_radio_read16(bcm, 0x0052); + backup[2] = bcm43xx_radio_read16(bcm, 0x0043); + backup[3] = bcm43xx_phy_read(bcm, 0x0030); + backup[4] = bcm43xx_phy_read(bcm, 0x0026); + backup[5] = bcm43xx_phy_read(bcm, 0x0015); + backup[6] = bcm43xx_phy_read(bcm, 0x002A); + backup[7] = bcm43xx_phy_read(bcm, 0x0020); + backup[8] = bcm43xx_phy_read(bcm, 0x005A); + backup[9] = bcm43xx_phy_read(bcm, 0x0059); + backup[10] = bcm43xx_phy_read(bcm, 0x0058); + backup[11] = bcm43xx_read16(bcm, 0x03E2); + backup[12] = bcm43xx_read16(bcm, 0x03E6); + backup[13] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); + + tmp = bcm43xx_radio_read16(bcm, 0x007A); + tmp &= (phy->rev >= 5) ? 0x007F : 0x000F; + bcm43xx_radio_write16(bcm, 0x007A, tmp); + bcm43xx_phy_write(bcm, 0x0030, 0x00FF); + bcm43xx_write16(bcm, 0x03EC, 0x7F7F); + bcm43xx_phy_write(bcm, 0x0026, 0x0000); + bcm43xx_phy_write(bcm, 0x0015, + bcm43xx_phy_read(bcm, 0x0015) | 0x0020); + bcm43xx_phy_write(bcm, 0x002A, 0x08A3); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); + + nrssi0 = (s16)bcm43xx_phy_read(bcm, 0x0027); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); + if (phy->rev >= 2) { + bcm43xx_write16(bcm, 0x03E6, 0x0040); + } else if (phy->rev == 0) { + bcm43xx_write16(bcm, 0x03E6, 0x0122); + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) & 0x2000); + } + bcm43xx_phy_write(bcm, 0x0020, 0x3F3F); + bcm43xx_phy_write(bcm, 0x0015, 0xF330); + bcm43xx_radio_write16(bcm, 0x005A, 0x0060); + bcm43xx_radio_write16(bcm, 0x0043, + bcm43xx_radio_read16(bcm, 0x0043) & 0x00F0); + bcm43xx_phy_write(bcm, 0x005A, 0x0480); + bcm43xx_phy_write(bcm, 0x0059, 0x0810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + udelay(20); + + nrssi1 = (s16)bcm43xx_phy_read(bcm, 0x0027); + bcm43xx_phy_write(bcm, 0x0030, backup[3]); + bcm43xx_radio_write16(bcm, 0x007A, backup[0]); + bcm43xx_write16(bcm, 0x03E2, backup[11]); + bcm43xx_phy_write(bcm, 0x0026, backup[4]); + bcm43xx_phy_write(bcm, 0x0015, backup[5]); + bcm43xx_phy_write(bcm, 0x002A, backup[6]); + bcm43xx_synth_pu_workaround(bcm, radio->channel); + if (phy->rev != 0) + bcm43xx_write16(bcm, 0x03F4, backup[13]); + + bcm43xx_phy_write(bcm, 0x0020, backup[7]); + bcm43xx_phy_write(bcm, 0x005A, backup[8]); + bcm43xx_phy_write(bcm, 0x0059, backup[9]); + bcm43xx_phy_write(bcm, 0x0058, backup[10]); + bcm43xx_radio_write16(bcm, 0x0052, backup[1]); + bcm43xx_radio_write16(bcm, 0x0043, backup[2]); + + if (nrssi0 == nrssi1) + radio->nrssislope = 0x00010000; + else + radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + + if (nrssi0 <= -4) { + radio->nrssi[0] = nrssi0; + radio->nrssi[1] = nrssi1; + } + break; + case BCM43xx_PHYTYPE_G: +//FIXME: Something is broken here. This is called when enabling WLAN interfmode. +// If this is done at runtime, I get an XMIT ERROR and transmission is +// broken. I guess some important register is overwritten by accident. +// The XMIT ERROR comes from the dummy_transmissions in set_gains. + if (radio->revision >= 9) + return; + if (radio->revision == 8) + bcm43xx_calc_nrssi_offset(bcm); + + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC); + backup[7] = bcm43xx_read16(bcm, 0x03E2); + bcm43xx_write16(bcm, 0x03E2, + bcm43xx_read16(bcm, 0x03E2) | 0x8000); + backup[0] = bcm43xx_radio_read16(bcm, 0x007A); + backup[1] = bcm43xx_radio_read16(bcm, 0x0052); + backup[2] = bcm43xx_radio_read16(bcm, 0x0043); + backup[3] = bcm43xx_phy_read(bcm, 0x0015); + backup[4] = bcm43xx_phy_read(bcm, 0x005A); + backup[5] = bcm43xx_phy_read(bcm, 0x0059); + backup[6] = bcm43xx_phy_read(bcm, 0x0058); + backup[8] = bcm43xx_read16(bcm, 0x03E6); + backup[9] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); + if (phy->rev >= 3) { + backup[10] = bcm43xx_phy_read(bcm, 0x002E); + backup[11] = bcm43xx_phy_read(bcm, 0x002F); + backup[12] = bcm43xx_phy_read(bcm, 0x080F); + backup[13] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_LO_CONTROL); + backup[14] = bcm43xx_phy_read(bcm, 0x0801); + backup[15] = bcm43xx_phy_read(bcm, 0x0060); + backup[16] = bcm43xx_phy_read(bcm, 0x0014); + backup[17] = bcm43xx_phy_read(bcm, 0x0478); + bcm43xx_phy_write(bcm, 0x002E, 0); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, 0); + switch (phy->rev) { + case 4: case 6: case 7: + bcm43xx_phy_write(bcm, 0x0478, + bcm43xx_phy_read(bcm, 0x0478) + | 0x0100); + bcm43xx_phy_write(bcm, 0x0801, + bcm43xx_phy_read(bcm, 0x0801) + | 0x0040); + break; + case 3: case 5: + bcm43xx_phy_write(bcm, 0x0801, + bcm43xx_phy_read(bcm, 0x0801) + & 0xFFBF); + break; + } + bcm43xx_phy_write(bcm, 0x0060, + bcm43xx_phy_read(bcm, 0x0060) + | 0x0040); + bcm43xx_phy_write(bcm, 0x0014, + bcm43xx_phy_read(bcm, 0x0014) + | 0x0200); + } + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0070); + bcm43xx_set_all_gains(bcm, 0, 8, 0); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x00F7); + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0811, + (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0030); + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0010); + } + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x0080); + udelay(20); + + nrssi0 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (nrssi0 >= 0x0020) + nrssi0 -= 0x0040; + + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) & 0x007F); + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0003, + (bcm43xx_phy_read(bcm, 0x0003) + & 0xFF9F) | 0x0040); + } + + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) + | 0x2000); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x000F); + bcm43xx_phy_write(bcm, 0x0015, 0xF330); + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF) | 0x0020); + bcm43xx_phy_write(bcm, 0x0811, + (bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF) | 0x0020); + } + + bcm43xx_set_all_gains(bcm, 3, 0, 1); + if (radio->revision == 8) { + bcm43xx_radio_write16(bcm, 0x0043, 0x001F); + } else { + tmp = bcm43xx_radio_read16(bcm, 0x0052) & 0xFF0F; + bcm43xx_radio_write16(bcm, 0x0052, tmp | 0x0060); + tmp = bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0; + bcm43xx_radio_write16(bcm, 0x0043, tmp | 0x0009); + } + bcm43xx_phy_write(bcm, 0x005A, 0x0480); + bcm43xx_phy_write(bcm, 0x0059, 0x0810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + udelay(20); + nrssi1 = (s16)((bcm43xx_phy_read(bcm, 0x047F) >> 8) & 0x003F); + if (nrssi1 >= 0x0020) + nrssi1 -= 0x0040; + if (nrssi0 == nrssi1) + radio->nrssislope = 0x00010000; + else + radio->nrssislope = 0x00400000 / (nrssi0 - nrssi1); + if (nrssi0 >= -4) { + radio->nrssi[0] = nrssi1; + radio->nrssi[1] = nrssi0; + } + if (phy->rev >= 3) { + bcm43xx_phy_write(bcm, 0x002E, backup[10]); + bcm43xx_phy_write(bcm, 0x002F, backup[11]); + bcm43xx_phy_write(bcm, 0x080F, backup[12]); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_LO_CONTROL, backup[13]); + } + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) & 0xFFCF); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) & 0xFFCF); + } + + bcm43xx_radio_write16(bcm, 0x007A, backup[0]); + bcm43xx_radio_write16(bcm, 0x0052, backup[1]); + bcm43xx_radio_write16(bcm, 0x0043, backup[2]); + bcm43xx_write16(bcm, 0x03E2, backup[7]); + bcm43xx_write16(bcm, 0x03E6, backup[8]); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[9]); + bcm43xx_phy_write(bcm, 0x0015, backup[3]); + bcm43xx_phy_write(bcm, 0x005A, backup[4]); + bcm43xx_phy_write(bcm, 0x0059, backup[5]); + bcm43xx_phy_write(bcm, 0x0058, backup[6]); + bcm43xx_synth_pu_workaround(bcm, radio->channel); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) | (0x0001 | 0x0002)); + bcm43xx_set_original_gains(bcm); + bcm43xx_phy_write(bcm, 0x0802, + bcm43xx_phy_read(bcm, 0x0802) | 0x8000); + if (phy->rev >= 3) { + bcm43xx_phy_write(bcm, 0x0801, backup[14]); + bcm43xx_phy_write(bcm, 0x0060, backup[15]); + bcm43xx_phy_write(bcm, 0x0014, backup[16]); + bcm43xx_phy_write(bcm, 0x0478, backup[17]); + } + bcm43xx_nrssi_mem_update(bcm); + bcm43xx_calc_nrssi_threshold(bcm); + break; + default: + assert(0); + } +} + +void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + s16 threshold; + s32 a, b; + int tmp; + s16 tmp16; + u16 tmp_u16; + + switch (phy->type) { + case BCM43xx_PHYTYPE_B: { + int radiotype = 0; + + if (phy->rev < 2) + return; + if (radio->version != 0x2050) + return; + if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) + return; + + tmp = radio->revision; + if ((radio->manufact == 0x175 && tmp == 5) || + (radio->manufact == 0x17F && (tmp == 3 || tmp == 4))) + radiotype = 1; + + if (radiotype == 1) { + threshold = bcm->current_core->radio->nrssi[1] - 5; + } else { + threshold = 40 * radio->nrssi[0]; + threshold += 33 * (radio->nrssi[1] - radio->nrssi[0]); + threshold += 20; + threshold /= 10; + } + threshold = limit_value(threshold, 0, 0x3E); + bcm43xx_phy_read(bcm, 0x0020); /* dummy read */ + bcm43xx_phy_write(bcm, 0x0020, (((u16)threshold) << 8) | 0x001C); + + if (radiotype == 1) { + bcm43xx_phy_write(bcm, 0x0087, 0x0E0D); + bcm43xx_phy_write(bcm, 0x0086, 0x0C0B); + bcm43xx_phy_write(bcm, 0x0085, 0x0A09); + bcm43xx_phy_write(bcm, 0x0084, 0x0808); + bcm43xx_phy_write(bcm, 0x0083, 0x0808); + bcm43xx_phy_write(bcm, 0x0082, 0x0604); + bcm43xx_phy_write(bcm, 0x0081, 0x0302); + bcm43xx_phy_write(bcm, 0x0080, 0x0100); + } + break; + } + case BCM43xx_PHYTYPE_G: + if (!phy->connected || + !(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) { + tmp16 = bcm43xx_nrssi_hw_read(bcm, 0x20); + if (tmp16 >= 0x20) + tmp16 -= 0x40; + if (tmp16 < 3) { + bcm43xx_phy_write(bcm, 0x048A, + (bcm43xx_phy_read(bcm, 0x048A) + & 0xF000) | 0x09EB); + } else { + bcm43xx_phy_write(bcm, 0x048A, + (bcm43xx_phy_read(bcm, 0x048A) + & 0xF000) | 0x0AED); + } + } else { + tmp = radio->interfmode; + if (tmp == BCM43xx_RADIO_INTERFMODE_NONWLAN) { + a = -13; + b = -17; + } else if (tmp == BCM43xx_RADIO_INTERFMODE_NONE && + !radio->aci_enable) { + a = -13; + b = -10; + } else { + a = -8; + b = -9; + } + a += 0x1B; + a *= radio->nrssi[1] - radio->nrssi[0]; + a += radio->nrssi[0] * 0x40; + a /= 64; + b += 0x1B; + b *= radio->nrssi[1] - radio->nrssi[0]; + b += radio->nrssi[0] * 0x40; + b /= 64; + + a = limit_value(a, -31, 31); + b = limit_value(b, -31, 31); + + tmp_u16 = bcm43xx_phy_read(bcm, 0x048A) & 0xF000; + tmp_u16 |= ((u32)a & 0x003F); + tmp_u16 |= (((u32)b & 0x003F) << 6); + bcm43xx_phy_write(bcm, 0x048A, tmp_u16); + } + break; + default: + assert(0); + } +} + +/* Helper macros to save on and restore values from the radio->interfstack */ +#ifdef stack_save +# undef stack_save +#endif +#ifdef stack_restore +# undef stack_restore +#endif +#define stack_save(value) \ + do { \ + assert(i < ARRAY_SIZE(radio->interfstack)); \ + stack[i++] = (value); \ + } while (0) + +#define stack_restore() \ + ({ \ + assert(i < ARRAY_SIZE(radio->interfstack)); \ + stack[i++]; \ + }) + +static void +bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm, + int mode) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + int i = 0; + u16 *stack = radio->interfstack; + u16 tmp, flipped; + + switch (mode) { + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) & 0x0800); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & ~0x4000); + break; + } + tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E); + flipped = flip_4bit(tmp); + if ((flipped >> 1) >= 4) + tmp = flipped - 3; + tmp = flip_4bit(tmp); + bcm43xx_radio_write16(bcm, 0x0078, tmp << 1); + + bcm43xx_calc_nrssi_threshold(bcm); + + if (bcm->current_core->rev < 5) { + stack_save(bcm43xx_phy_read(bcm, 0x0406)); + bcm43xx_phy_write(bcm, 0x0406, 0x7E28); + } else { + stack_save(bcm43xx_phy_read(bcm, 0x04C0)); + stack_save(bcm43xx_phy_read(bcm, 0x04C1)); + bcm43xx_phy_write(bcm, 0x04C0, 0x3E04); + bcm43xx_phy_write(bcm, 0x04C1, 0x0640); + } + + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) | 0x0800); + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | 0x1000); + + stack_save(bcm43xx_phy_read(bcm, 0x04A0)); + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) & 0xC0C0) | 0x0008); + stack_save(bcm43xx_phy_read(bcm, 0x04A1)); + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0C0) | 0x0605); + stack_save(bcm43xx_phy_read(bcm, 0x04A2)); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) & 0xC0C0) | 0x0204); + stack_save(bcm43xx_phy_read(bcm, 0x04A8)); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0403); + stack_save(bcm43xx_phy_read(bcm, 0x04AB)); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0504); + + stack_save(bcm43xx_phy_read(bcm, 0x04A7)); + bcm43xx_phy_write(bcm, 0x04A7, 0x0002); + stack_save(bcm43xx_phy_read(bcm, 0x04A3)); + bcm43xx_phy_write(bcm, 0x04A3, 0x287A); + stack_save(bcm43xx_phy_read(bcm, 0x04A9)); + bcm43xx_phy_write(bcm, 0x04A9, 0x2027); + stack_save(bcm43xx_phy_read(bcm, 0x0493)); + bcm43xx_phy_write(bcm, 0x0493, 0x32F5); + stack_save(bcm43xx_phy_read(bcm, 0x04AA)); + bcm43xx_phy_write(bcm, 0x04AA, 0x2027); + stack_save(bcm43xx_phy_read(bcm, 0x04AC)); + bcm43xx_phy_write(bcm, 0x04AC, 0x32F5); + break; + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + if (bcm43xx_phy_read(bcm, 0x0033) == 0x0800) + break; + + radio->aci_enable = 1; + + stack_save(bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD)); + stack_save(bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)); + if (bcm->current_core->rev < 5) { + stack_save(bcm43xx_phy_read(bcm, 0x0406)); + } else { + stack_save(bcm43xx_phy_read(bcm, 0x04C0)); + stack_save(bcm43xx_phy_read(bcm, 0x04C1)); + } + stack_save(bcm43xx_phy_read(bcm, 0x0033)); + stack_save(bcm43xx_phy_read(bcm, 0x04A7)); + stack_save(bcm43xx_phy_read(bcm, 0x04A3)); + stack_save(bcm43xx_phy_read(bcm, 0x04A9)); + stack_save(bcm43xx_phy_read(bcm, 0x04AA)); + stack_save(bcm43xx_phy_read(bcm, 0x04AC)); + stack_save(bcm43xx_phy_read(bcm, 0x0493)); + stack_save(bcm43xx_phy_read(bcm, 0x04A1)); + stack_save(bcm43xx_phy_read(bcm, 0x04A0)); + stack_save(bcm43xx_phy_read(bcm, 0x04A2)); + stack_save(bcm43xx_phy_read(bcm, 0x048A)); + stack_save(bcm43xx_phy_read(bcm, 0x04A8)); + stack_save(bcm43xx_phy_read(bcm, 0x04AB)); + + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) & 0xEFFF); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xEFFF) | 0x0002); + + bcm43xx_phy_write(bcm, 0x04A7, 0x0800); + bcm43xx_phy_write(bcm, 0x04A3, 0x287A); + bcm43xx_phy_write(bcm, 0x04A9, 0x2027); + bcm43xx_phy_write(bcm, 0x0493, 0x32F5); + bcm43xx_phy_write(bcm, 0x04AA, 0x2027); + bcm43xx_phy_write(bcm, 0x04AC, 0x32F5); + + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFC0) | 0x001A); + if (bcm->current_core->rev < 5) { + bcm43xx_phy_write(bcm, 0x0406, 0x280D); + } else { + bcm43xx_phy_write(bcm, 0x04C0, 0x0640); + bcm43xx_phy_write(bcm, 0x04C1, 0x00A9); + } + + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0FF) | 0x1800); + bcm43xx_phy_write(bcm, 0x04A1, + (bcm43xx_phy_read(bcm, 0x04A1) & 0xFFC0) | 0x0016); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0900); + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0700); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x000D); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) & 0xCFFF) | 0x1000); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) & 0xF0FF) | 0x0A00); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) & 0xCFFF) | 0x1000); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0800); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) & 0xFFCF) | 0x0010); + bcm43xx_phy_write(bcm, 0x04AB, + (bcm43xx_phy_read(bcm, 0x04AB) & 0xFFF0) | 0x0006); + + bcm43xx_calc_nrssi_slope(bcm); + break; + default: + assert(0); + } +} + +static void +bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, + int mode) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + int i = 0; + u16 *stack = radio->interfstack; + u16 tmp, flipped; + + switch (mode) { + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + if (phy->rev != 1) { + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x4000); + break; + } + tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E); + flipped = flip_4bit(tmp); + if ((flipped >> 1) >= 0x000C) + tmp = flipped + 3; + tmp = flip_4bit(tmp); + bcm43xx_radio_write16(bcm, 0x0078, tmp << 1); + + bcm43xx_calc_nrssi_threshold(bcm); + + if (bcm->current_core->rev < 5) { + bcm43xx_phy_write(bcm, 0x0406, stack_restore()); + } else { + bcm43xx_phy_write(bcm, 0x04C0, stack_restore()); + bcm43xx_phy_write(bcm, 0x04C1, stack_restore()); + } + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); + + if (!bcm->bad_frames_preempt) + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) & ~(1 << 11)); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x4000); + bcm43xx_phy_write(bcm, 0x04A0, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A1, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A2, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A8, stack_restore()); + bcm43xx_phy_write(bcm, 0x04AB, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A7, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A3, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A9, stack_restore()); + bcm43xx_phy_write(bcm, 0x0493, stack_restore()); + bcm43xx_phy_write(bcm, 0x04AA, stack_restore()); + bcm43xx_phy_write(bcm, 0x04AC, stack_restore()); + break; + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + if (bcm43xx_phy_read(bcm, 0x0033) != 0x0800) + break; + + radio->aci_enable = 0; + + bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, stack_restore()); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, stack_restore()); + if (bcm->current_core->rev < 5) { + bcm43xx_phy_write(bcm, 0x0406, stack_restore()); + } else { + bcm43xx_phy_write(bcm, 0x04C0, stack_restore()); + bcm43xx_phy_write(bcm, 0x04C1, stack_restore()); + } + bcm43xx_phy_write(bcm, 0x0033, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A7, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A3, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A9, stack_restore()); + bcm43xx_phy_write(bcm, 0x04AA, stack_restore()); + bcm43xx_phy_write(bcm, 0x04AC, stack_restore()); + bcm43xx_phy_write(bcm, 0x0493, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A1, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A0, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A2, stack_restore()); + bcm43xx_phy_write(bcm, 0x04A8, stack_restore()); + bcm43xx_phy_write(bcm, 0x04AB, stack_restore()); + + bcm43xx_calc_nrssi_slope(bcm); + break; + default: + assert(0); + } +} + +#undef stack_save +#undef stack_restore + +int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, + int mode) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + int currentmode; + + if ((phy->type != BCM43xx_PHYTYPE_G) || + (phy->rev == 0) || + (!phy->connected)) + return -ENODEV; + + radio->aci_wlan_automatic = 0; + switch (mode) { + case BCM43xx_RADIO_INTERFMODE_AUTOWLAN: + radio->aci_wlan_automatic = 1; + if (radio->aci_enable) + mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; + else + mode = BCM43xx_RADIO_INTERFMODE_NONE; + break; + case BCM43xx_RADIO_INTERFMODE_NONE: + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + break; + default: + return -EINVAL; + } + + currentmode = radio->interfmode; + if (currentmode == mode) + return 0; + if (currentmode != BCM43xx_RADIO_INTERFMODE_NONE) + bcm43xx_radio_interference_mitigation_disable(bcm, currentmode); + + if (mode == BCM43xx_RADIO_INTERFMODE_NONE) { + radio->aci_enable = 0; + radio->aci_hw_rssi = 0; + } else + bcm43xx_radio_interference_mitigation_enable(bcm, mode); + radio->interfmode = mode; + + return 0; +} + +static u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm) +{ + u16 reg, index, ret; + + reg = bcm43xx_radio_read16(bcm, 0x0060); + index = (reg & 0x001E) >> 1; + ret = rcc_table[index] << 1; + ret |= (reg & 0x0001); + ret |= 0x0020; + + return ret; +} + +u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 backup[19] = { 0 }; + u16 ret; + u16 i, j; + u32 tmp1 = 0, tmp2 = 0; + + backup[0] = bcm43xx_radio_read16(bcm, 0x0043); + backup[14] = bcm43xx_radio_read16(bcm, 0x0051); + backup[15] = bcm43xx_radio_read16(bcm, 0x0052); + backup[1] = bcm43xx_phy_read(bcm, 0x0015); + backup[16] = bcm43xx_phy_read(bcm, 0x005A); + backup[17] = bcm43xx_phy_read(bcm, 0x0059); + backup[18] = bcm43xx_phy_read(bcm, 0x0058); + if (phy->type == BCM43xx_PHYTYPE_B) { + backup[2] = bcm43xx_phy_read(bcm, 0x0030); + backup[3] = bcm43xx_read16(bcm, 0x03EC); + bcm43xx_phy_write(bcm, 0x0030, 0x00FF); + bcm43xx_write16(bcm, 0x03EC, 0x3F3F); + } else { + if (phy->connected) { + backup[4] = bcm43xx_phy_read(bcm, 0x0811); + backup[5] = bcm43xx_phy_read(bcm, 0x0812); + backup[6] = bcm43xx_phy_read(bcm, 0x0814); + backup[7] = bcm43xx_phy_read(bcm, 0x0815); + backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS); + backup[9] = bcm43xx_phy_read(bcm, 0x0802); + bcm43xx_phy_write(bcm, 0x0814, + (bcm43xx_phy_read(bcm, 0x0814) | 0x0003)); + bcm43xx_phy_write(bcm, 0x0815, + (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC)); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF)); + bcm43xx_phy_write(bcm, 0x0802, + (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC)); + bcm43xx_phy_write(bcm, 0x0811, 0x01B3); + bcm43xx_phy_write(bcm, 0x0812, 0x0FB2); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, + (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000)); + } + backup[10] = bcm43xx_phy_read(bcm, 0x0035); + bcm43xx_phy_write(bcm, 0x0035, + (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F)); + backup[11] = bcm43xx_read16(bcm, 0x03E6); + backup[12] = bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT); + + // Initialization + if (phy->version == 0) { + bcm43xx_write16(bcm, 0x03E6, 0x0122); + } else { + if (phy->version >= 2) + bcm43xx_write16(bcm, 0x03E6, 0x0040); + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000)); + } + + ret = bcm43xx_radio_calibrationvalue(bcm); + + if (phy->type == BCM43xx_PHYTYPE_B) + bcm43xx_radio_write16(bcm, 0x0078, 0x0003); + + bcm43xx_phy_write(bcm, 0x0015, 0xBFAF); + bcm43xx_phy_write(bcm, 0x002B, 0x1403); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x00B2); + bcm43xx_phy_write(bcm, 0x0015, 0xBFA0); + bcm43xx_radio_write16(bcm, 0x0051, + (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004)); + bcm43xx_radio_write16(bcm, 0x0052, 0x0000); + bcm43xx_radio_write16(bcm, 0x0043, + bcm43xx_radio_read16(bcm, 0x0043) | 0x0009); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + + for (i = 0; i < 16; i++) { + bcm43xx_phy_write(bcm, 0x005A, 0x0480); + bcm43xx_phy_write(bcm, 0x0059, 0xC810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + udelay(10); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); + udelay(10); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); + udelay(10); + tmp1 += bcm43xx_phy_read(bcm, 0x002D); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + } + + tmp1++; + tmp1 >>= 9; + udelay(10); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + + for (i = 0; i < 16; i++) { + bcm43xx_radio_write16(bcm, 0x0078, (flip_4bit(i) << 1) | 0x0020); + backup[13] = bcm43xx_radio_read16(bcm, 0x0078); + udelay(10); + for (j = 0; j < 16; j++) { + bcm43xx_phy_write(bcm, 0x005A, 0x0D80); + bcm43xx_phy_write(bcm, 0x0059, 0xC810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + udelay(10); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); + udelay(10); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */ + bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); + udelay(10); + tmp2 += bcm43xx_phy_read(bcm, 0x002D); + bcm43xx_phy_write(bcm, 0x0058, 0x0000); + if (phy->connected) + bcm43xx_phy_write(bcm, 0x0812, 0x30B2); + bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); + } + tmp2++; + tmp2 >>= 8; + if (tmp1 < tmp2) + break; + } + + /* Restore the registers */ + bcm43xx_phy_write(bcm, 0x0015, backup[1]); + bcm43xx_radio_write16(bcm, 0x0051, backup[14]); + bcm43xx_radio_write16(bcm, 0x0052, backup[15]); + bcm43xx_radio_write16(bcm, 0x0043, backup[0]); + bcm43xx_phy_write(bcm, 0x005A, backup[16]); + bcm43xx_phy_write(bcm, 0x0059, backup[17]); + bcm43xx_phy_write(bcm, 0x0058, backup[18]); + bcm43xx_write16(bcm, 0x03E6, backup[11]); + if (phy->version != 0) + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, backup[12]); + bcm43xx_phy_write(bcm, 0x0035, backup[10]); + bcm43xx_radio_selectchannel(bcm, radio->channel, 1); + if (phy->type == BCM43xx_PHYTYPE_B) { + bcm43xx_phy_write(bcm, 0x0030, backup[2]); + bcm43xx_write16(bcm, 0x03EC, backup[3]); + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, + (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF)); + if (phy->connected) { + bcm43xx_phy_write(bcm, 0x0811, backup[4]); + bcm43xx_phy_write(bcm, 0x0812, backup[5]); + bcm43xx_phy_write(bcm, 0x0814, backup[6]); + bcm43xx_phy_write(bcm, 0x0815, backup[7]); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]); + bcm43xx_phy_write(bcm, 0x0802, backup[9]); + } + } + if (i >= 15) + ret = backup[13]; + + return ret; +} + +void bcm43xx_radio_init2060(struct bcm43xx_private *bcm) +{ + int err; + + bcm43xx_radio_write16(bcm, 0x0004, 0x00C0); + bcm43xx_radio_write16(bcm, 0x0005, 0x0008); + bcm43xx_radio_write16(bcm, 0x0009, 0x0040); + bcm43xx_radio_write16(bcm, 0x0005, 0x00AA); + bcm43xx_radio_write16(bcm, 0x0032, 0x008F); + bcm43xx_radio_write16(bcm, 0x0006, 0x008F); + bcm43xx_radio_write16(bcm, 0x0034, 0x008F); + bcm43xx_radio_write16(bcm, 0x002C, 0x0007); + bcm43xx_radio_write16(bcm, 0x0082, 0x0080); + bcm43xx_radio_write16(bcm, 0x0080, 0x0000); + bcm43xx_radio_write16(bcm, 0x003F, 0x00DA); + bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008); + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0010); + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020); + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020); + udelay(400); + + bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020) | 0x0010); + udelay(400); + + bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008) | 0x0008); + bcm43xx_radio_write16(bcm, 0x0085, bcm43xx_radio_read16(bcm, 0x0085) & ~0x0010); + bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008); + bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040); + bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040) | 0x0040); + bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0008) | 0x0008); + bcm43xx_phy_write(bcm, 0x0063, 0xDDC6); + bcm43xx_phy_write(bcm, 0x0069, 0x07BE); + bcm43xx_phy_write(bcm, 0x006A, 0x0000); + + err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_A, 0); + assert(err == 0); + udelay(1000); +} + +static inline +u16 freq_r3A_value(u16 frequency) +{ + u16 value; + + if (frequency < 5091) + value = 0x0040; + else if (frequency < 5321) + value = 0x0000; + else if (frequency < 5806) + value = 0x0080; + else + value = 0x0040; + + return value; +} + +void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm) +{ + static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; + static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; + u16 tmp = bcm43xx_radio_read16(bcm, 0x001E); + int i, j; + + for (i = 0; i < 5; i++) { + for (j = 0; j < 5; j++) { + if (tmp == (data_high[i] << 4 | data_low[j])) { + bcm43xx_phy_write(bcm, 0x0069, (i - j) << 8 | 0x00C0); + return; + } + } + } +} + +int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, + u8 channel, + int synthetic_pu_workaround) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + u16 r8, tmp; + u16 freq; + + if ((radio->manufact == 0x17F) && + (radio->version == 0x2060) && + (radio->revision == 1)) { + if (channel > 200) + return -EINVAL; + freq = channel2freq_a(channel); + + r8 = bcm43xx_radio_read16(bcm, 0x0008); + bcm43xx_write16(bcm, 0x03F0, freq); + bcm43xx_radio_write16(bcm, 0x0008, r8); + + TODO();//TODO: write max channel TX power? to Radio 0x2D + tmp = bcm43xx_radio_read16(bcm, 0x002E); + tmp &= 0x0080; + TODO();//TODO: OR tmp with the Power out estimation for this channel? + bcm43xx_radio_write16(bcm, 0x002E, tmp); + + if (freq >= 4920 && freq <= 5500) { + /* + * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; + * = (freq * 0.025862069 + */ + r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ + } + bcm43xx_radio_write16(bcm, 0x0007, (r8 << 4) | r8); + bcm43xx_radio_write16(bcm, 0x0020, (r8 << 4) | r8); + bcm43xx_radio_write16(bcm, 0x0021, (r8 << 4) | r8); + bcm43xx_radio_write16(bcm, 0x0022, + (bcm43xx_radio_read16(bcm, 0x0022) + & 0x000F) | (r8 << 4)); + bcm43xx_radio_write16(bcm, 0x002A, (r8 << 4)); + bcm43xx_radio_write16(bcm, 0x002B, (r8 << 4)); + bcm43xx_radio_write16(bcm, 0x0008, + (bcm43xx_radio_read16(bcm, 0x0008) + & 0x00F0) | (r8 << 4)); + bcm43xx_radio_write16(bcm, 0x0029, + (bcm43xx_radio_read16(bcm, 0x0029) + & 0xFF0F) | 0x00B0); + bcm43xx_radio_write16(bcm, 0x0035, 0x00AA); + bcm43xx_radio_write16(bcm, 0x0036, 0x0085); + bcm43xx_radio_write16(bcm, 0x003A, + (bcm43xx_radio_read16(bcm, 0x003A) + & 0xFF20) | freq_r3A_value(freq)); + bcm43xx_radio_write16(bcm, 0x003D, + bcm43xx_radio_read16(bcm, 0x003D) & 0x00FF); + bcm43xx_radio_write16(bcm, 0x0081, + (bcm43xx_radio_read16(bcm, 0x0081) + & 0xFF7F) | 0x0080); + bcm43xx_radio_write16(bcm, 0x0035, + bcm43xx_radio_read16(bcm, 0x0035) & 0xFFEF); + bcm43xx_radio_write16(bcm, 0x0035, + (bcm43xx_radio_read16(bcm, 0x0035) + & 0xFFEF) | 0x0010); + bcm43xx_radio_set_tx_iq(bcm); + TODO(); //TODO: TSSI2dbm workaround + bcm43xx_phy_xmitpower(bcm);//FIXME correct? + } else { + if ((channel < 1) || (channel > 14)) + return -EINVAL; + + if (synthetic_pu_workaround) + bcm43xx_synth_pu_workaround(bcm, channel); + + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, + channel2freq_bg(channel)); + + if (channel == 14) { + if (bcm->sprom.locale == BCM43xx_LOCALE_JAPAN) { + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET) + & ~(1 << 7)); + } else { + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET) + | (1 << 7)); + } + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) + | (1 << 11)); + } else { + bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, + bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) + & 0xF7BF); + } + } + + radio->channel = channel; + //XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states + // that 2000 usecs might suffice. + udelay(8000); + + return 0; +} + +void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val) +{ + u16 tmp; + + val <<= 8; + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0022) & 0xFCFF; + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0022, tmp | val); + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x03A8) & 0xFCFF; + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x03A8, tmp | val); + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0054) & 0xFCFF; + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0054, tmp | val); +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */ +static u16 bcm43xx_get_txgain_base_band(u16 txpower) +{ + u16 ret; + + assert(txpower <= 63); + + if (txpower >= 54) + ret = 2; + else if (txpower >= 49) + ret = 4; + else if (txpower >= 44) + ret = 5; + else + ret = 6; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */ +static u16 bcm43xx_get_txgain_freq_power_amp(u16 txpower) +{ + u16 ret; + + assert(txpower <= 63); + + if (txpower >= 32) + ret = 0; + else if (txpower >= 25) + ret = 1; + else if (txpower >= 20) + ret = 2; + else if (txpower >= 12) + ret = 3; + else + ret = 4; + + return ret; +} + +/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */ +static u16 bcm43xx_get_txgain_dac(u16 txpower) +{ + u16 ret; + + assert(txpower <= 63); + + if (txpower >= 54) + ret = txpower - 53; + else if (txpower >= 49) + ret = txpower - 42; + else if (txpower >= 44) + ret = txpower - 37; + else if (txpower >= 32) + ret = txpower - 32; + else if (txpower >= 25) + ret = txpower - 20; + else if (txpower >= 20) + ret = txpower - 13; + else if (txpower >= 12) + ret = txpower - 8; + else + ret = txpower; + + return ret; +} + +void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower) +{ + u16 pamp, base, dac, ilt; + + txpower = limit_value(txpower, 0, 63); + + pamp = bcm43xx_get_txgain_freq_power_amp(txpower); + pamp <<= 5; + pamp &= 0x00E0; + bcm43xx_phy_write(bcm, 0x0019, pamp); + + base = bcm43xx_get_txgain_base_band(txpower); + base &= 0x000F; + bcm43xx_phy_write(bcm, 0x0017, base | 0x0020); + + ilt = bcm43xx_ilt_read16(bcm, 0x3001); + ilt &= 0x0007; + + dac = bcm43xx_get_txgain_dac(txpower); + dac <<= 3; + dac |= ilt; + + bcm43xx_ilt_write16(bcm, 0x3001, dac); + + bcm->current_core->radio->txpower[0] = txpower; + + TODO(); + //TODO: FuncPlaceholder (Adjust BB loft cancel) +} + +void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, + u16 baseband_attenuation, u16 radio_attenuation, + u16 txpower) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + + if (baseband_attenuation == 0xFFFF) + baseband_attenuation = radio->txpower[0]; + else + radio->txpower[0] = baseband_attenuation; + if (radio_attenuation == 0xFFFF) + radio_attenuation = radio->txpower[1]; + else + radio->txpower[1] = radio_attenuation; + if (txpower == 0xFFFF) + txpower = radio->txpower[2]; + else + radio->txpower[2] = txpower; + + assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11); + if (radio->revision < 6) + assert(/*radio_attenuation >= 0 &&*/ radio_attenuation <= 9); + else + assert(/* radio_attenuation >= 0 &&*/ radio_attenuation <= 31); + assert(/*txpower >= 0 &&*/ txpower <= 7); + + bcm43xx_phy_set_baseband_attenuation(bcm, baseband_attenuation); + bcm43xx_radio_write16(bcm, 0x0043, radio_attenuation); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0064, radio_attenuation); + if (radio->version == 0x2050) { + bcm43xx_radio_write16(bcm, 0x0052, + (bcm43xx_radio_read16(bcm, 0x0052) & 0xFF8F) + | (txpower << 4)); + } + if (phy->type == BCM43xx_PHYTYPE_G) + bcm43xx_phy_lo_adjust(bcm, 0); +} + + +void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + int err; + + if (radio->enabled) + return; + + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + bcm43xx_radio_write16(bcm, 0x0004, 0x00C0); + bcm43xx_radio_write16(bcm, 0x0005, 0x0008); + bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) & 0xFFF7); + bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) & 0xFFF7); + bcm43xx_radio_init2060(bcm); + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + bcm43xx_phy_write(bcm, 0x0015, 0x8000); + bcm43xx_phy_write(bcm, 0x0015, 0xCC00); + bcm43xx_phy_write(bcm, 0x0015, (phy->connected ? 0x00C0 : 0x0000)); + err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 1); + assert(err == 0); + break; + default: + assert(0); + } + radio->enabled = 1; + dprintk(KERN_INFO PFX "Radio turned on\n"); +} + +void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + + if (phy->type == BCM43xx_PHYTYPE_A) { + bcm43xx_radio_write16(bcm, 0x0004, 0x00FF); + bcm43xx_radio_write16(bcm, 0x0005, 0x00FB); + bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) | 0x0008); + bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) | 0x0008); + } + if (phy->type == BCM43xx_PHYTYPE_G && bcm->current_core->rev >= 5) { + bcm43xx_phy_write(bcm, 0x0811, bcm43xx_phy_read(bcm, 0x0811) | 0x008C); + bcm43xx_phy_write(bcm, 0x0812, bcm43xx_phy_read(bcm, 0x0812) & 0xFF73); + } else + bcm43xx_phy_write(bcm, 0x0015, 0xAA00); + radio->enabled = 0; + dprintk(KERN_INFO PFX "Radio turned off\n"); +} + +void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm) +{ + switch (bcm->current_core->phy->type) { + case BCM43xx_PHYTYPE_A: + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0068, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x006a, 0x7F7F); + break; + case BCM43xx_PHYTYPE_B: + case BCM43xx_PHYTYPE_G: + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0058, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x005a, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0070, 0x7F7F); + bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0072, 0x7F7F); + break; + } +} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h new file mode 100644 index 00000000000..89fe2928214 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h @@ -0,0 +1,93 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_RADIO_H_ +#define BCM43xx_RADIO_H_ + +#include "bcm43xx.h" + + +#define BCM43xx_RADIO_DEFAULT_CHANNEL_A 36 +#define BCM43xx_RADIO_DEFAULT_CHANNEL_BG 6 + +/* Force antenna 0. */ +#define BCM43xx_RADIO_TXANTENNA_0 0 +/* Force antenna 1. */ +#define BCM43xx_RADIO_TXANTENNA_1 1 +/* Use the RX antenna, that was selected for the most recently + * received good PLCP header. + */ +#define BCM43xx_RADIO_TXANTENNA_LASTPLCP 3 +#define BCM43xx_RADIO_TXANTENNA_DEFAULT BCM43xx_RADIO_TXANTENNA_LASTPLCP + +#define BCM43xx_RADIO_INTERFMODE_NONE 0 +#define BCM43xx_RADIO_INTERFMODE_NONWLAN 1 +#define BCM43xx_RADIO_INTERFMODE_MANUALWLAN 2 +#define BCM43xx_RADIO_INTERFMODE_AUTOWLAN 3 + + +void bcm43xx_radio_lock(struct bcm43xx_private *bcm); +void bcm43xx_radio_unlock(struct bcm43xx_private *bcm); + +u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset); +void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val); + +u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm); +void bcm43xx_radio_init2060(struct bcm43xx_private *bcm); + +void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm); +void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm); + +int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel, + int synthetic_pu_workaround); + +void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower); +void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, + u16 baseband_attenuation, u16 attenuation, + u16 txpower); +void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val); + +void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm); + +u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel); +u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm); + +int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, int mode); + +void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm); +void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm); +s16 bcm43xx_nrssi_hw_read(struct bcm43xx_private *bcm, u16 offset); +void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val); +void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val); +void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm); + +void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm); + +#endif /* BCM43xx_RADIO_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c new file mode 100644 index 00000000000..fe6409a9090 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -0,0 +1,1099 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include +#include /* for capable() */ +#include + +#include "bcm43xx.h" +#include "bcm43xx_wx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_radio.h" + +/* Define to enable a printk on each wx handler function invocation */ +//#define BCM43xx_WX_DEBUG + + +#ifdef BCM43xx_WX_DEBUG +# define printk_wx printk +#else +# define printk_wx(x...) do { /* nothing */ } while (0) +#endif +#define wx_enter() printk_wx(KERN_INFO PFX "WX handler called: %s\n", __FUNCTION__); + +#define MAX_WX_STRING 80 + + +static int bcm43xx_wx_get_name(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int i, nr_80211; + struct bcm43xx_phyinfo *phy; + char suffix[7] = { 0 }; + int have_a = 0, have_b = 0, have_g = 0; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + nr_80211 = bcm43xx_num_80211_cores(bcm); + for (i = 0; i < nr_80211; i++) { + phy = bcm->phy + i; + switch (phy->type) { + case BCM43xx_PHYTYPE_A: + have_a = 1; + break; + case BCM43xx_PHYTYPE_G: + have_g = 1; + case BCM43xx_PHYTYPE_B: + have_b = 1; + break; + default: + assert(0); + } + } + spin_unlock_irqrestore(&bcm->lock, flags); + + i = 0; + if (have_a) { + suffix[i++] = 'a'; + suffix[i++] = '/'; + } + if (have_b) { + suffix[i++] = 'b'; + suffix[i++] = '/'; + } + if (have_g) { + suffix[i++] = 'g'; + suffix[i++] = '/'; + } + if (i != 0) + suffix[i - 1] = '\0'; + + snprintf(data->name, IFNAMSIZ, "IEEE 802.11%s", suffix); + + return 0; +} + +static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct ieee80211softmac_device *softmac = bcm->softmac; + unsigned long flags; + u8 channel; + int freq; + int err = 0; + + wx_enter(); + + if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { + channel = data->freq.m; + freq = bcm43xx_channel_to_freq(bcm, channel); + } else { + channel = bcm43xx_freq_to_channel(bcm, data->freq.m); + freq = data->freq.m; + } + if (!bcm43xx_is_valid_channel(bcm, channel)) + return -EINVAL; + + spin_lock_irqsave(&bcm->lock, flags); + if (bcm->initialized) { + //ieee80211softmac_disassoc(softmac, $REASON); + bcm43xx_mac_suspend(bcm); + err = bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_mac_enable(bcm); + } else + bcm->current_core->radio->initial_channel = channel; + spin_unlock_irqrestore(&bcm->lock, flags); + if (!err) + printk_wx(KERN_INFO PFX "Selected channel: %d\n", channel); + + return err; +} + +static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int err = -ENODEV; + u16 channel; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + channel = bcm->current_core->radio->channel; + if (channel == 0xFF) { + assert(!bcm->initialized); + channel = bcm->current_core->radio->initial_channel; + if (channel == 0xFF) + goto out_unlock; + } + assert(channel > 0 && channel <= 1000); + data->freq.e = 1; + data->freq.m = bcm43xx_channel_to_freq(bcm, channel) * 100000; + data->freq.flags = 1; + + err = 0; +out_unlock: + spin_unlock_irqrestore(&bcm->lock, flags); + + return err; +} + +static int bcm43xx_wx_set_mode(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int mode; + + wx_enter(); + + mode = data->mode; + if (mode == IW_MODE_AUTO) + mode = BCM43xx_INITIAL_IWMODE; + + spin_lock_irqsave(&bcm->lock, flags); + if (bcm->ieee->iw_mode != mode) + bcm43xx_set_iwmode(bcm, mode); + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_get_mode(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + data->mode = bcm->ieee->iw_mode; + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_set_sensitivity(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + wx_enter(); + /*TODO*/ + return 0; +} + +static int bcm43xx_wx_get_sensitivity(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + wx_enter(); + /*TODO*/ + return 0; +} + +static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct iw_range *range = (struct iw_range *)extra; + const struct ieee80211_geo *geo; + unsigned long flags; + int i, j; + + wx_enter(); + + data->data.length = sizeof(*range); + memset(range, 0, sizeof(*range)); + + //TODO: What about 802.11b? + /* 54Mb/s == ~27Mb/s payload throughput (802.11g) */ + range->throughput = 27 * 1000 * 1000; + + range->max_qual.qual = 100; + /* TODO: Real max RSSI */ + range->max_qual.level = 0; + range->max_qual.noise = 0; + range->max_qual.updated = 7; + + range->avg_qual.qual = 70; + range->avg_qual.level = 0; + range->avg_qual.noise = 0; + range->avg_qual.updated = 7; + + range->min_rts = BCM43xx_MIN_RTS_THRESHOLD; + range->max_rts = BCM43xx_MAX_RTS_THRESHOLD; + range->min_frag = MIN_FRAG_THRESHOLD; + range->max_frag = MAX_FRAG_THRESHOLD; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = WEP_KEYS; + + range->we_version_compiled = WIRELESS_EXT; + range->we_version_source = 16; + + spin_lock_irqsave(&bcm->lock, flags); + + range->num_bitrates = 0; + i = 0; + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A || + bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + range->num_bitrates = 8; + range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_12MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_18MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_24MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_36MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB; + range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB; + } + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B || + bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + range->num_bitrates += 4; + range->bitrate[i++] = IEEE80211_CCK_RATE_1MB; + range->bitrate[i++] = IEEE80211_CCK_RATE_2MB; + range->bitrate[i++] = IEEE80211_CCK_RATE_5MB; + range->bitrate[i++] = IEEE80211_CCK_RATE_11MB; + } + + geo = ieee80211_get_geo(bcm->ieee); + range->num_channels = geo->a_channels + geo->bg_channels; + j = 0; + for (i = 0; i < geo->a_channels; i++) { + if (j == IW_MAX_FREQUENCIES) + break; + range->freq[j].i = j + 1; + range->freq[j].m = geo->a[i].freq;//FIXME? + range->freq[j].e = 1; + j++; + } + for (i = 0; i < geo->bg_channels; i++) { + if (j == IW_MAX_FREQUENCIES) + break; + range->freq[j].i = j + 1; + range->freq[j].m = geo->bg[i].freq;//FIXME? + range->freq[j].e = 1; + j++; + } + range->num_frequency = j; + + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_set_nick(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + size_t len; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); + memcpy(bcm->nick, extra, len); + bcm->nick[len] = '\0'; + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_get_nick(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + size_t len; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + len = strlen(bcm->nick) + 1; + memcpy(extra, bcm->nick, len); + data->data.length = (__u16)len; + data->data.flags = 1; + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_set_rts(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int err = -EINVAL; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + if (data->rts.disabled) { + bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; + err = 0; + } else { + if (data->rts.value >= BCM43xx_MIN_RTS_THRESHOLD && + data->rts.value <= BCM43xx_MAX_RTS_THRESHOLD) { + bcm->rts_threshold = data->rts.value; + err = 0; + } + } + spin_unlock_irqrestore(&bcm->lock, flags); + + return err; +} + +static int bcm43xx_wx_get_rts(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + data->rts.value = bcm->rts_threshold; + data->rts.fixed = 0; + data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_set_frag(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int err = -EINVAL; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + if (data->frag.disabled) { + bcm->ieee->fts = MAX_FRAG_THRESHOLD; + err = 0; + } else { + if (data->frag.value >= MIN_FRAG_THRESHOLD && + data->frag.value <= MAX_FRAG_THRESHOLD) { + bcm->ieee->fts = data->frag.value & ~0x1; + err = 0; + } + } + spin_unlock_irqrestore(&bcm->lock, flags); + + return err; +} + +static int bcm43xx_wx_get_frag(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + data->frag.value = bcm->ieee->fts; + data->frag.fixed = 0; + data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int err = -ENODEV; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + if (!bcm->initialized) + goto out_unlock; + if (data->power.disabled != (!(bcm->current_core->radio->enabled))) { + if (data->power.disabled) + bcm43xx_radio_turn_off(bcm); + else + bcm43xx_radio_turn_on(bcm); + } + //TODO: set txpower. + err = 0; + +out_unlock: + spin_unlock_irqrestore(&bcm->lock, flags); + + return err; +} + +static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); +//TODO data->power.value = ??? + data->power.fixed = 1; + data->power.flags = IW_TXPOW_DBM; + data->power.disabled = !(bcm->current_core->radio->enabled); + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_set_retry(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + wx_enter(); + /*TODO*/ + return 0; +} + +static int bcm43xx_wx_get_retry(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + wx_enter(); + /*TODO*/ + return 0; +} + +static int bcm43xx_wx_set_encoding(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err; + + wx_enter(); + + err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra); + + return err; +} + +static int bcm43xx_wx_set_encodingext(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err; + + wx_enter(); + + err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra); + + return err; +} + +static int bcm43xx_wx_get_encoding(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err; + + wx_enter(); + + err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra); + + return err; +} + +static int bcm43xx_wx_get_encodingext(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err; + + wx_enter(); + + err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra); + + return err; +} + +static int bcm43xx_wx_set_power(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + wx_enter(); + /*TODO*/ + return 0; +} + +static int bcm43xx_wx_get_power(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + wx_enter(); + /*TODO*/ + return 0; +} + +static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int mode, err = 0; + + wx_enter(); + + mode = *((int *)extra); + switch (mode) { + case 0: + mode = BCM43xx_RADIO_INTERFMODE_NONE; + break; + case 1: + mode = BCM43xx_RADIO_INTERFMODE_NONWLAN; + break; + case 2: + mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; + break; + case 3: + mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; + break; + default: + printk(KERN_ERR PFX "set_interfmode allowed parameters are: " + "0 => None, 1 => Non-WLAN, 2 => WLAN, " + "3 => Auto-WLAN\n"); + return -EINVAL; + } + + spin_lock_irqsave(&bcm->lock, flags); + if (bcm->initialized) { + err = bcm43xx_radio_set_interference_mitigation(bcm, mode); + if (err) { + printk(KERN_ERR PFX "Interference Mitigation not " + "supported by device\n"); + } + } else { + if (mode == BCM43xx_RADIO_INTERFMODE_AUTOWLAN) { + printk(KERN_ERR PFX "Interference Mitigation mode Auto-WLAN " + "not supported while the interface is down.\n"); + err = -ENODEV; + } else + bcm->current_core->radio->interfmode = mode; + } + spin_unlock_irqrestore(&bcm->lock, flags); + + return err; +} + +static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int mode; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + mode = bcm->current_core->radio->interfmode; + spin_unlock_irqrestore(&bcm->lock, flags); + + switch (mode) { + case BCM43xx_RADIO_INTERFMODE_NONE: + strncpy(extra, "0 (No Interference Mitigation)", MAX_WX_STRING); + break; + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + strncpy(extra, "1 (Non-WLAN Interference Mitigation)", MAX_WX_STRING); + break; + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + strncpy(extra, "2 (WLAN Interference Mitigation)", MAX_WX_STRING); + break; + default: + assert(0); + } + data->data.length = strlen(extra) + 1; + + return 0; +} + +static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int on; + + wx_enter(); + + on = *((int *)extra); + spin_lock_irqsave(&bcm->lock, flags); + bcm->short_preamble = !!on; + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int on; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + on = bcm->short_preamble; + spin_unlock_irqrestore(&bcm->lock, flags); + + if (on) + strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); + else + strncpy(extra, "0 (Short Preamble disabled)", MAX_WX_STRING); + data->data.length = strlen(extra) + 1; + + return 0; +} + +static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int on; + + wx_enter(); + + on = *((int *)extra); + spin_lock_irqsave(&bcm->lock, flags); + bcm->ieee->host_encrypt = !!on; + bcm->ieee->host_decrypt = !!on; + bcm->ieee->host_build_iv = !on; + + spin_unlock_irqrestore(&bcm->lock, flags); + + return 0; +} + +static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + int on; + + wx_enter(); + + spin_lock_irqsave(&bcm->lock, flags); + on = bcm->ieee->host_encrypt; + spin_unlock_irqrestore(&bcm->lock, flags); + + if (on) + strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); + else + strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING); + data->data.length = strlen(extra + 1); + + return 0; +} + +/* Enough buffer to hold a hexdump of the sprom data. */ +#define SPROM_BUFFERSIZE 512 + +static int sprom2hex(const u16 *sprom, char *dump) +{ + int i, pos = 0; + + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + pos += snprintf(dump + pos, SPROM_BUFFERSIZE - pos - 1, + "%04X", swab16(sprom[i]) & 0xFFFF); + } + + return pos + 1; +} + +static int hex2sprom(u16 *sprom, const char *dump, unsigned int len) +{ + char tmp[5] = { 0 }; + int cnt = 0; + unsigned long parsed; + u8 crc, expected_crc; + + if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2) + return -EINVAL; + while (cnt < BCM43xx_SPROM_SIZE) { + memcpy(tmp, dump, 4); + dump += 4; + parsed = simple_strtoul(tmp, NULL, 16); + sprom[cnt++] = swab16((u16)parsed); + } + + crc = bcm43xx_sprom_crc(sprom); + expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; + if (crc != expected_crc) { + printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n"); + return -EINVAL; + } + + return 0; +} + +static int bcm43xx_wx_sprom_read(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err = -EPERM, i; + u16 *sprom; + unsigned long flags; + + if (!capable(CAP_SYS_RAWIO)) + goto out; + + err = -ENOMEM; + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), + GFP_KERNEL); + if (!sprom) + goto out; + + spin_lock_irqsave(&bcm->lock, flags); + err = -ENODEV; + if (!bcm->initialized) { + spin_unlock_irqrestore(&bcm->lock, flags); + goto out_kfree; + } + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) + sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2)); + spin_unlock_irqrestore(&bcm->lock, flags); + + data->data.length = sprom2hex(sprom, extra); + + err = 0; +out_kfree: + kfree(sprom); +out: + return err; +} + +static int bcm43xx_wx_sprom_write(struct net_device *net_dev, + struct iw_request_info *info, + union iwreq_data *data, + char *extra) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + int err = -EPERM; + u16 *sprom; + unsigned long flags; + char *input; + unsigned int len; + u32 spromctl; + int i; + + if (!capable(CAP_SYS_RAWIO)) + goto out; + + err = -ENOMEM; + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), + GFP_KERNEL); + if (!sprom) + goto out; + + len = data->data.length; + extra[len - 1] = '\0'; + input = strchr(extra, ':'); + if (input) { + input++; + len -= input - extra; + } else + input = extra; + err = hex2sprom(sprom, input, len); + if (err) + goto out_kfree; + + spin_lock_irqsave(&bcm->lock, flags); + err = -ENODEV; + if (!bcm->initialized) { + spin_unlock_irqrestore(&bcm->lock, flags); + goto out_kfree; + } + + printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl); + if (err) { + printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + goto out_unlock; + } + spromctl |= 0x10; /* SPROM WRITE enable. */ + bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); + if (err) { + printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + goto out_unlock; + } + /* We must burn lots of CPU cycles here, but that does not + * really matter as one does not write the SPROM every other minute... + */ + printk(KERN_INFO PFX "[ 0%%"); + mdelay(500); + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + if (i == 16) + printk("25%%"); + else if (i == 32) + printk("50%%"); + else if (i == 48) + printk("75%%"); + else if (i % 2) + printk("."); +//TODO bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); + mdelay(20); + } + spromctl &= ~0x10; /* SPROM WRITE enable. */ + bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); + if (err) { + printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + goto out_unlock; + } + mdelay(500); + printk("100%% ]\n"); + printk(KERN_INFO PFX "SPROM written.\n"); + err = 0; +out_unlock: + spin_unlock_irqrestore(&bcm->lock, flags); +out_kfree: + kfree(sprom); +out: + return err; +} + + +#ifdef WX +# undef WX +#endif +#define WX(ioctl) [(ioctl) - SIOCSIWCOMMIT] +static const iw_handler bcm43xx_wx_handlers[] = { + /* Wireless Identification */ + WX(SIOCGIWNAME) = bcm43xx_wx_get_name, + /* Basic operations */ + WX(SIOCSIWFREQ) = bcm43xx_wx_set_channelfreq, + WX(SIOCGIWFREQ) = bcm43xx_wx_get_channelfreq, + WX(SIOCSIWMODE) = bcm43xx_wx_set_mode, + WX(SIOCGIWMODE) = bcm43xx_wx_get_mode, + /* Informative stuff */ + WX(SIOCGIWRANGE) = bcm43xx_wx_get_rangeparams, + /* Access Point manipulation */ + WX(SIOCSIWAP) = ieee80211softmac_wx_set_wap, + WX(SIOCGIWAP) = ieee80211softmac_wx_get_wap, + WX(SIOCSIWSCAN) = ieee80211softmac_wx_trigger_scan, + WX(SIOCGIWSCAN) = ieee80211softmac_wx_get_scan_results, + /* 802.11 specific support */ + WX(SIOCSIWESSID) = ieee80211softmac_wx_set_essid, + WX(SIOCGIWESSID) = ieee80211softmac_wx_get_essid, + WX(SIOCSIWNICKN) = bcm43xx_wx_set_nick, + WX(SIOCGIWNICKN) = bcm43xx_wx_get_nick, + /* Other parameters */ + WX(SIOCSIWRATE) = ieee80211softmac_wx_set_rate, + WX(SIOCGIWRATE) = ieee80211softmac_wx_get_rate, + WX(SIOCSIWRTS) = bcm43xx_wx_set_rts, + WX(SIOCGIWRTS) = bcm43xx_wx_get_rts, + WX(SIOCSIWFRAG) = bcm43xx_wx_set_frag, + WX(SIOCGIWFRAG) = bcm43xx_wx_get_frag, + WX(SIOCSIWTXPOW) = bcm43xx_wx_set_xmitpower, + WX(SIOCGIWTXPOW) = bcm43xx_wx_get_xmitpower, +//TODO WX(SIOCSIWRETRY) = bcm43xx_wx_set_retry, +//TODO WX(SIOCGIWRETRY) = bcm43xx_wx_get_retry, + /* Encoding */ + WX(SIOCSIWENCODE) = bcm43xx_wx_set_encoding, + WX(SIOCGIWENCODE) = bcm43xx_wx_get_encoding, + WX(SIOCSIWENCODEEXT) = bcm43xx_wx_set_encodingext, + WX(SIOCGIWENCODEEXT) = bcm43xx_wx_get_encodingext, + /* Power saving */ +//TODO WX(SIOCSIWPOWER) = bcm43xx_wx_set_power, +//TODO WX(SIOCGIWPOWER) = bcm43xx_wx_get_power, + WX(SIOCSIWGENIE) = ieee80211softmac_wx_set_genie, + WX(SIOCGIWGENIE) = ieee80211softmac_wx_get_genie, + WX(SIOCSIWAUTH) = ieee80211_wx_set_auth, + WX(SIOCGIWAUTH) = ieee80211_wx_get_auth, +}; +#undef WX + +static const iw_handler bcm43xx_priv_wx_handlers[] = { + /* Set Interference Mitigation Mode. */ + bcm43xx_wx_set_interfmode, + /* Get Interference Mitigation Mode. */ + bcm43xx_wx_get_interfmode, + /* Enable/Disable Short Preamble mode. */ + bcm43xx_wx_set_shortpreamble, + /* Get Short Preamble mode. */ + bcm43xx_wx_get_shortpreamble, + /* Enable/Disable Software Encryption mode */ + bcm43xx_wx_set_swencryption, + /* Get Software Encryption mode */ + bcm43xx_wx_get_swencryption, + /* Write SRPROM data. */ + bcm43xx_wx_sprom_write, + /* Read SPROM data. */ + bcm43xx_wx_sprom_read, +}; + +#define PRIV_WX_SET_INTERFMODE (SIOCIWFIRSTPRIV + 0) +#define PRIV_WX_GET_INTERFMODE (SIOCIWFIRSTPRIV + 1) +#define PRIV_WX_SET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 2) +#define PRIV_WX_GET_SHORTPREAMBLE (SIOCIWFIRSTPRIV + 3) +#define PRIV_WX_SET_SWENCRYPTION (SIOCIWFIRSTPRIV + 4) +#define PRIV_WX_GET_SWENCRYPTION (SIOCIWFIRSTPRIV + 5) +#define PRIV_WX_SPROM_WRITE (SIOCIWFIRSTPRIV + 6) +#define PRIV_WX_SPROM_READ (SIOCIWFIRSTPRIV + 7) + +#define PRIV_WX_DUMMY(ioctl) \ + { \ + .cmd = (ioctl), \ + .name = "__unused" \ + } + +static const struct iw_priv_args bcm43xx_priv_wx_args[] = { + { + .cmd = PRIV_WX_SET_INTERFMODE, + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + .name = "set_interfmode", + }, + { + .cmd = PRIV_WX_GET_INTERFMODE, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, + .name = "get_interfmode", + }, + { + .cmd = PRIV_WX_SET_SHORTPREAMBLE, + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + .name = "set_shortpreambl", + }, + { + .cmd = PRIV_WX_GET_SHORTPREAMBLE, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, + .name = "get_shortpreambl", + }, + { + .cmd = PRIV_WX_SET_SWENCRYPTION, + .set_args = IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, + .name = "set_swencryption", + }, + { + .cmd = PRIV_WX_GET_SWENCRYPTION, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | MAX_WX_STRING, + .name = "get_swencryption", + }, + { + .cmd = PRIV_WX_SPROM_WRITE, + .set_args = IW_PRIV_TYPE_CHAR | SPROM_BUFFERSIZE, + .name = "write_sprom", + }, + { + .cmd = PRIV_WX_SPROM_READ, + .get_args = IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | SPROM_BUFFERSIZE, + .name = "read_sprom", + }, +}; + +const struct iw_handler_def bcm43xx_wx_handlers_def = { + .standard = bcm43xx_wx_handlers, + .num_standard = ARRAY_SIZE(bcm43xx_wx_handlers), + .num_private = ARRAY_SIZE(bcm43xx_priv_wx_handlers), + .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args), + .private = bcm43xx_priv_wx_handlers, + .private_args = bcm43xx_priv_wx_args, +}; + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.h b/drivers/net/wireless/bcm43xx/bcm43xx_wx.h new file mode 100644 index 00000000000..1f29ff3aa4c --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.h @@ -0,0 +1,36 @@ +/* + + Broadcom BCM43xx wireless driver + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + Some parts of the code in this file are derived from the ipw2200 + driver Copyright(c) 2003 - 2004 Intel Corporation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#ifndef BCM43xx_WX_H_ +#define BCM43xx_WX_H_ + +extern const struct iw_handler_def bcm43xx_wx_handlers_def; + +#endif /* BCM43xx_WX_H_ */ -- cgit v1.2.3 From 70e5e983f8a3f801a96bfeb0682cd2955ec3c8ce Mon Sep 17 00:00:00 2001 From: "John W. Linville" Date: Mon, 23 Jan 2006 17:00:39 -0500 Subject: [PATCH] bcm43xx: patch Kconfig and wireless/Makefile for import Patch Kconfig and wireless/Makefile to merge bcm43xx 'properly' Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 8 ++++++++ drivers/net/wireless/Makefile | 1 + 2 files changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index fd17aa8491b..7c7dca112bf 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -501,6 +501,14 @@ config PRISM54 source "drivers/net/wireless/hostap/Kconfig" +config BCM43XX + tristate "Broadcom BCM43xx wireless support" + depends on PCI && IEEE80211 && NET_RADIO && IEEE80211_SOFTMAC && EXPERIMENTAL + select FW_LOADER + ---help--- + This is an experimental driver for the Broadcom 43xx wireless chip, + found in the Apple Airport Extreme and various other devices. + # yes, this works even when no drivers are selected config NET_WIRELESS bool diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 3a6f7ba326c..c8677987936 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o obj-$(CONFIG_PRISM54) += prism54/ obj-$(CONFIG_HOSTAP) += hostap/ +obj-$(CONFIG_BCM43XX) += bcm43xx/ # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o -- cgit v1.2.3 From ea72ab229fe9cdfe3d3f70a6e64d98c725294b24 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 27 Jan 2006 17:26:20 +0100 Subject: [PATCH] bcm43xx: sync with svn.berlios.de Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 198 ++++++++++++--------------- drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 11 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 7 +- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 8 +- 5 files changed, 102 insertions(+), 124 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index df19fbfa9ea..af5c27f9bfd 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -214,7 +214,9 @@ static int alloc_ringmemory(struct bcm43xx_dmaring *ring) return -ENOMEM; } if (ring->dmabase + BCM43xx_DMA_RINGMEMSIZE > BCM43xx_DMA_BUSADDRMAX) { - printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G\n"); + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RINGMEMORY >1G " + "(0x%08x, len: %lu)\n", + ring->dmabase, BCM43xx_DMA_RINGMEMSIZE); dma_free_coherent(dev, BCM43xx_DMA_RINGMEMSIZE, ring->vbase, ring->dmabase); return -ENOMEM; @@ -261,13 +263,6 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, return 0; } -static inline int dmacontroller_rx_reset(struct bcm43xx_dmaring *ring) -{ - assert(!ring->tx); - - return bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base); -} - /* Reset the RX DMA channel */ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, u16 mmio_base) @@ -308,13 +303,6 @@ int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, return 0; } -static inline int dmacontroller_tx_reset(struct bcm43xx_dmaring *ring) -{ - assert(ring->tx); - - return bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base); -} - static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, struct bcm43xx_dmadesc *desc, struct bcm43xx_dmadesc_meta *meta, @@ -337,7 +325,9 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, if (unlikely(dmaaddr + ring->rx_buffersize > BCM43xx_DMA_BUSADDRMAX)) { unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0); dev_kfree_skb_any(skb); - printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G\n"); + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA RX SKB >1G " + "(0x%08x, len: %u)\n", + dmaaddr, ring->rx_buffersize); return -ENOMEM; } meta->skb = skb; @@ -365,7 +355,7 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring) { int i, err = -ENOMEM; - struct bcm43xx_dmadesc *desc = NULL; + struct bcm43xx_dmadesc *desc; struct bcm43xx_dmadesc_meta *meta; for (i = 0; i < ring->nr_slots; i++) { @@ -375,24 +365,20 @@ static int alloc_initial_descbuffers(struct bcm43xx_dmaring *ring) err = setup_rx_descbuffer(ring, desc, meta, GFP_KERNEL); if (err) goto err_unwind; - - assert(ring->used_slots <= ring->nr_slots); } ring->used_slots = ring->nr_slots; - err = 0; out: return err; err_unwind: - for ( ; i >= 0; i--) { + for (i--; i >= 0; i--) { desc = ring->vbase + i; meta = ring->meta + i; unmap_descbuffer(ring, meta->dmaaddr, ring->rx_buffersize, 0); dev_kfree_skb(meta->skb); } - ring->used_slots = 0; goto out; } @@ -442,13 +428,13 @@ out: static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring) { if (ring->tx) { - dmacontroller_tx_reset(ring); + bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base); /* Zero out Transmit Descriptor ring address. */ bcm43xx_write32(ring->bcm, ring->mmio_base + BCM43xx_DMA_TX_DESC_RING, 0x00000000); } else { - dmacontroller_rx_reset(ring); + bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base); /* Zero out Receive Descriptor ring address. */ bcm43xx_write32(ring->bcm, ring->mmio_base + BCM43xx_DMA_RX_DESC_RING, @@ -508,9 +494,7 @@ struct bcm43xx_dmaring * bcm43xx_setup_dmaring(struct bcm43xx_private *bcm, if (bcm->pci_dev->bus->number == 0) ring->memoffset = 0; #endif - - - spin_lock_init(&ring->lock); + ring->bcm = bcm; ring->nr_slots = nr_descriptor_slots; ring->suspend_mark = ring->nr_slots * BCM43xx_TXSUSPEND_PERCENT / 100; @@ -578,22 +562,25 @@ static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring) void bcm43xx_dma_free(struct bcm43xx_private *bcm) { - bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring1); - bcm->current_core->dma->rx_ring1 = NULL; - bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring0); - bcm->current_core->dma->rx_ring0 = NULL; - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring3); - bcm->current_core->dma->tx_ring3 = NULL; - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring2); - bcm->current_core->dma->tx_ring2 = NULL; - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring1); - bcm->current_core->dma->tx_ring1 = NULL; - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring0); - bcm->current_core->dma->tx_ring0 = NULL; + struct bcm43xx_dma *dma = bcm->current_core->dma; + + bcm43xx_destroy_dmaring(dma->rx_ring1); + dma->rx_ring1 = NULL; + bcm43xx_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; } int bcm43xx_dma_init(struct bcm43xx_private *bcm) { + struct bcm43xx_dma *dma = bcm->current_core->dma; struct bcm43xx_dmaring *ring; int err = -ENOMEM; @@ -602,39 +589,39 @@ int bcm43xx_dma_init(struct bcm43xx_private *bcm) BCM43xx_TXRING_SLOTS, 1); if (!ring) goto out; - bcm->current_core->dma->tx_ring0 = ring; + dma->tx_ring0 = ring; ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA2_BASE, BCM43xx_TXRING_SLOTS, 1); if (!ring) goto err_destroy_tx0; - bcm->current_core->dma->tx_ring1 = ring; + dma->tx_ring1 = ring; ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA3_BASE, BCM43xx_TXRING_SLOTS, 1); if (!ring) goto err_destroy_tx1; - bcm->current_core->dma->tx_ring2 = ring; + dma->tx_ring2 = ring; ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, BCM43xx_TXRING_SLOTS, 1); if (!ring) goto err_destroy_tx2; - bcm->current_core->dma->tx_ring3 = ring; + dma->tx_ring3 = ring; /* setup RX DMA channels. */ ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA1_BASE, BCM43xx_RXRING_SLOTS, 0); if (!ring) goto err_destroy_tx3; - bcm->current_core->dma->rx_ring0 = ring; + dma->rx_ring0 = ring; if (bcm->current_core->rev < 5) { ring = bcm43xx_setup_dmaring(bcm, BCM43xx_MMIO_DMA4_BASE, BCM43xx_RXRING_SLOTS, 0); if (!ring) goto err_destroy_rx0; - bcm->current_core->dma->rx_ring1 = ring; + dma->rx_ring1 = ring; } dprintk(KERN_INFO PFX "DMA initialized\n"); @@ -643,27 +630,26 @@ out: return err; err_destroy_rx0: - bcm43xx_destroy_dmaring(bcm->current_core->dma->rx_ring0); - bcm->current_core->dma->rx_ring0 = NULL; + bcm43xx_destroy_dmaring(dma->rx_ring0); + dma->rx_ring0 = NULL; err_destroy_tx3: - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring3); - bcm->current_core->dma->tx_ring3 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring3); + dma->tx_ring3 = NULL; err_destroy_tx2: - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring2); - bcm->current_core->dma->tx_ring2 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring2); + dma->tx_ring2 = NULL; err_destroy_tx1: - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring1); - bcm->current_core->dma->tx_ring1 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring1); + dma->tx_ring1 = NULL; err_destroy_tx0: - bcm43xx_destroy_dmaring(bcm->current_core->dma->tx_ring0); - bcm->current_core->dma->tx_ring0 = NULL; + bcm43xx_destroy_dmaring(dma->tx_ring0); + dma->tx_ring0 = NULL; goto out; } /* Generate a cookie for the TX header. */ -static inline -u16 generate_cookie(struct bcm43xx_dmaring *ring, - int slot) +static u16 generate_cookie(struct bcm43xx_dmaring *ring, + int slot) { u16 cookie = 0x0000; @@ -693,24 +679,25 @@ u16 generate_cookie(struct bcm43xx_dmaring *ring, } /* Inspect a cookie and find out to which controller/slot it belongs. */ -static inline +static struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm, u16 cookie, int *slot) { + struct bcm43xx_dma *dma = bcm->current_core->dma; struct bcm43xx_dmaring *ring = NULL; switch (cookie & 0xF000) { case 0x0000: - ring = bcm->current_core->dma->tx_ring0; + ring = dma->tx_ring0; break; case 0x1000: - ring = bcm->current_core->dma->tx_ring1; + ring = dma->tx_ring1; break; case 0x2000: - ring = bcm->current_core->dma->tx_ring2; + ring = dma->tx_ring2; break; case 0x3000: - ring = bcm->current_core->dma->tx_ring3; + ring = dma->tx_ring3; break; default: assert(0); @@ -721,8 +708,8 @@ struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm, return ring; } -static inline void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, - int slot) +static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, + int slot) { /* Everything is ready to start. Buffers are DMA mapped and * associated with slots. @@ -736,11 +723,10 @@ static inline void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, (u32)(slot * sizeof(struct bcm43xx_dmadesc))); } -static inline -int dma_tx_fragment(struct bcm43xx_dmaring *ring, - struct sk_buff *skb, - struct ieee80211_txb *txb, - u8 cur_frag) +static int dma_tx_fragment(struct bcm43xx_dmaring *ring, + struct sk_buff *skb, + struct ieee80211_txb *txb, + u8 cur_frag) { int slot; struct bcm43xx_dmadesc *desc; @@ -777,7 +763,9 @@ int dma_tx_fragment(struct bcm43xx_dmaring *ring, meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); if (unlikely(meta->dmaaddr + skb->len > BCM43xx_DMA_BUSADDRMAX)) { return_slot(ring, slot); - printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G\n"); + printk(KERN_ERR PFX ">>>FATAL ERROR<<< DMA TX SKB >1G " + "(0x%08x, len: %u)\n", + meta->dmaaddr, skb->len); return -ENOMEM; } @@ -797,14 +785,15 @@ int dma_tx_fragment(struct bcm43xx_dmaring *ring, return 0; } -static inline int dma_transfer_txb(struct bcm43xx_dmaring *ring, - struct ieee80211_txb *txb) +int bcm43xx_dma_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) { /* We just received a packet from the kernel network subsystem. * Add headers and DMA map the memory. Poke * the device to send the stuff. * Note that this is called from atomic context. */ + struct bcm43xx_dmaring *ring = bcm->current_core->dma->tx_ring1; u8 i; struct sk_buff *skb; @@ -818,8 +807,6 @@ static inline int dma_transfer_txb(struct bcm43xx_dmaring *ring, return -ENOMEM; } - assert(irqs_disabled()); - spin_lock(&ring->lock); for (i = 0; i < txb->nr_frags; i++) { skb = txb->fragments[i]; /* We do not free the skb, as it is freed as @@ -829,22 +816,12 @@ static inline int dma_transfer_txb(struct bcm43xx_dmaring *ring, dma_tx_fragment(ring, skb, txb, i); //TODO: handle failure of dma_tx_fragment } - spin_unlock(&ring->lock); return 0; } -int fastcall -bcm43xx_dma_transfer_txb(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb) -{ - return dma_transfer_txb(bcm->current_core->dma->tx_ring1, - txb); -} - -void fastcall -bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status) +void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) { struct bcm43xx_dmaring *ring; struct bcm43xx_dmadesc *desc; @@ -855,9 +832,6 @@ bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, ring = parse_cookie(bcm, status->cookie, &slot); assert(ring); assert(ring->tx); - assert(irqs_disabled()); - spin_lock(&ring->lock); - assert(get_desc_ctl(ring->vbase + slot) & BCM43xx_DMADTOR_FRAMESTART); while (1) { assert(slot >= 0 && slot < ring->nr_slots); @@ -877,13 +851,10 @@ bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, slot = next_slot(ring, slot); } bcm->stats.last_tx = jiffies; - - spin_unlock(&ring->lock); } -static inline -void dma_rx(struct bcm43xx_dmaring *ring, - int *slot) +static void dma_rx(struct bcm43xx_dmaring *ring, + int *slot) { struct bcm43xx_dmadesc *desc; struct bcm43xx_dmadesc_meta *meta; @@ -928,8 +899,12 @@ void dma_rx(struct bcm43xx_dmaring *ring, barrier(); len = le16_to_cpu(rxhdr->frame_length); } while (len == 0 && i++ < 5); - if (len == 0) + if (unlikely(len == 0)) { + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); goto drop; + } } if (unlikely(len > ring->rx_buffersize)) { /* The data did not fit into one descriptor buffer @@ -937,15 +912,24 @@ void dma_rx(struct bcm43xx_dmaring *ring, * This should never happen, as we try to allocate buffers * big enough. So simply ignore this packet. */ - int cnt = 1; - s32 tmp = len - ring->rx_buffersize; - - for ( ; tmp > 0; tmp -= ring->rx_buffersize) { + int cnt = 0; + s32 tmp = len; + + while (1) { + desc = ring->vbase + *slot; + meta = ring->meta + *slot; + /* recycle the descriptor buffer. */ + sync_descbuffer_for_device(ring, meta->dmaaddr, + ring->rx_buffersize); *slot = next_slot(ring, *slot); cnt++; + tmp -= ring->rx_buffersize; + if (tmp <= 0) + break; } - printkl(KERN_ERR PFX "DMA RX buffer too small. %d dropped.\n", - cnt); + printkl(KERN_ERR PFX "DMA RX buffer too small " + "(len: %u, buffer: %u, nr-dropped: %d)\n", + len, ring->rx_buffersize, cnt); goto drop; } len -= IEEE80211_FCS_LEN; @@ -954,6 +938,8 @@ void dma_rx(struct bcm43xx_dmaring *ring, err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC); if (unlikely(err)) { dprintkl(KERN_ERR PFX "DMA RX: setup_rx_descbuffer() failed\n"); + sync_descbuffer_for_device(ring, dmaaddr, + ring->rx_buffersize); goto drop; } @@ -971,8 +957,7 @@ drop: return; } -void fastcall -bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) +void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) { u32 status; u16 descptr; @@ -982,9 +967,6 @@ bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) #endif assert(!ring->tx); - assert(irqs_disabled()); - spin_lock(&ring->lock); - status = bcm43xx_read32(ring->bcm, ring->mmio_base + BCM43xx_DMA_RX_STATUS); descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK); current_slot = descptr / sizeof(struct bcm43xx_dmadesc); @@ -1002,8 +984,6 @@ bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) ring->mmio_base + BCM43xx_DMA_RX_DESC_INDEX, (u32)(slot * sizeof(struct bcm43xx_dmadesc))); ring->current_slot = slot; - - spin_unlock(&ring->lock); } /* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h index e32cf68f8e1..93e99d61f2e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -122,7 +122,6 @@ struct bcm43xx_dmadesc_meta { }; struct bcm43xx_dmaring { - spinlock_t lock; struct bcm43xx_private *bcm; /* Kernel virtual base address of the ring memory. */ struct bcm43xx_dmadesc *vbase; @@ -166,11 +165,11 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, u16 dmacontroller_mmio_base); -int FASTCALL(bcm43xx_dma_transfer_txb(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb)); -void FASTCALL(bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status)); +void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status); -void FASTCALL(bcm43xx_dma_rx(struct bcm43xx_dmaring *ring)); +int bcm43xx_dma_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb); +void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring); #endif /* BCM43xx_DMA_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index be60a6509f2..4b4e60a22c0 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -4097,7 +4097,6 @@ int fastcall bcm43xx_rx(struct bcm43xx_private *bcm, } frame_ctl = le16_to_cpu(wlhdr->frame_ctl); - if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) { frame_ctl &= ~IEEE80211_FCTL_PROTECTED; wlhdr->frame_ctl = cpu_to_le16(frame_ctl); @@ -4113,12 +4112,12 @@ int fastcall bcm43xx_rx(struct bcm43xx_private *bcm, skb_trim(skb, skb->len - 4); stats.len -= 8; } - /* do _not_ use wlhdr again without reassigning it */ + wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); } switch (WLAN_FC_GET_TYPE(frame_ctl)) { case IEEE80211_FTYPE_MGMT: - ieee80211_rx_mgt(bcm->ieee, skb->data, &stats); + ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats); break; case IEEE80211_FTYPE_DATA: if (is_packet_for_us) @@ -4143,7 +4142,7 @@ static inline int bcm43xx_tx(struct bcm43xx_private *bcm, if (bcm->pio_mode) err = bcm43xx_pio_transfer_txb(bcm, txb); else - err = bcm43xx_dma_transfer_txb(bcm, txb); + err = bcm43xx_dma_tx(bcm, txb); return err; } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 41b9cd7fc9e..f5e7a6ab93c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -1161,7 +1161,7 @@ void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm) phy->minlowsigpos[1] += 0x0101; bcm43xx_phy_write(bcm, 0x002F, phy->minlowsigpos[1]); - if (radio->version == 2053) { + if (radio->version == 0x2053) { bcm43xx_phy_write(bcm, 0x000A, regstack[2]); bcm43xx_phy_write(bcm, 0x002A, regstack[3]); bcm43xx_phy_write(bcm, 0x0035, regstack[4]); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 1e65658552b..5ce6acef2c4 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -467,8 +467,8 @@ static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0003, (bcm43xx_phy_read(bcm, 0x0003) & 0xFF9F) | 0x0040); - bcm43xx_phy_write(bcm, 0x007A, - bcm43xx_phy_read(bcm, 0x007A) | 0x000F); + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) | 0x000F); bcm43xx_set_all_gains(bcm, 3, 0, 1); bcm43xx_radio_write16(bcm, 0x0043, (bcm43xx_radio_read16(bcm, 0x0043) @@ -761,8 +761,8 @@ void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0802, bcm43xx_phy_read(bcm, 0x0802) | (0x0001 | 0x0002)); bcm43xx_set_original_gains(bcm); - bcm43xx_phy_write(bcm, 0x0802, - bcm43xx_phy_read(bcm, 0x0802) | 0x8000); + bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x8000); if (phy->rev >= 3) { bcm43xx_phy_write(bcm, 0x0801, backup[14]); bcm43xx_phy_write(bcm, 0x0060, backup[15]); -- cgit v1.2.3 From 4a2a2792d0cb3f2797ff179beef7b8c2981979c2 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 27 Jan 2006 17:33:15 +0100 Subject: [PATCH] bcm43xx: remove linux version compatibility code. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 23 ----------------------- 1 file changed, 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index aca1601e5b4..38e75ed2b65 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -935,27 +935,4 @@ int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 valu __value; \ }) - -/* - * Compatibility stuff follows - */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 15) -# error "The bcm43xx driver does not support kernels < 2.6.15" -# error "The driver will _NOT_ compile on your kernel. Please upgrade to the latest 2.6 kernel." -# error "DO NOT COMPLAIN ABOUT BUGS. UPDATE FIRST AND TRY AGAIN." -#else -# if !defined(CONFIG_IEEE80211_MODULE) && !defined(CONFIG_IEEE80211) -# error "Generic IEEE 802.11 Networking Stack (CONFIG_IEEE80211) not available." -# endif -#endif -#ifdef IEEE80211SOFTMAC_API -# if IEEE80211SOFTMAC_API != 0 -# warning "Incompatible SoftMAC subsystem installed." -# endif -#else -# error "The bcm43xx driver requires the SoftMAC subsystem." -# error "SEE >>>>>> http://softmac.sipsolutions.net/ <<<<<<" -#endif - #endif /* BCM43xx_H_ */ -- cgit v1.2.3 From 08ccd883f536d81d380522106c67bd5d7043fa4a Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 27 Jan 2006 17:37:05 +0100 Subject: [PATCH] bcm43xx: Move README file to Documentation directory. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/README | 36 ------------------------------------ 1 file changed, 36 deletions(-) delete mode 100644 drivers/net/wireless/bcm43xx/README (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/README b/drivers/net/wireless/bcm43xx/README deleted file mode 100644 index 64d9022de7f..00000000000 --- a/drivers/net/wireless/bcm43xx/README +++ /dev/null @@ -1,36 +0,0 @@ - - BCM43xx Linux Driver Project - ============================ - -About this software -------------------- - -The goal of this project is to develop a linux driver for Broadcom -BCM43xx chips, based on the specification at -http://bcm-specs.sipsolutions.net/ - -The project page is http://bcm43xx.berlios.de/ - - -Requirements ------------- - -1) Linux Kernel 2.6.15 or later - http://www.kernel.org/ - - You may want to configure your kernel with: - - CONFIG_DEBUG_FS (optional): - -> Kernel hacking - -> Debug Filesystem - -2) SoftMAC IEEE 802.11 Networking Stack extension and patched ieee80211 - modules: - http://softmac.sipsolutions.net/ - -3) Firmware Files - - Please try fwcutter. Fwcutter can extract the firmware from various - binary driver files. It supports driver files from Windows, MacOS and - Linux. You can get fwcutter from http://bcm43xx.berlios.de/. - Also, fwcutter comes with a README file for further instructions. -- cgit v1.2.3 From dda207ae2da37032524bbdd7a0133c37f2907ae8 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Fri, 27 Jan 2006 17:39:44 +0100 Subject: [PATCH] bcm43xx: remove redundant COPYING file. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/COPYING | 340 ----------------------------------- 1 file changed, 340 deletions(-) delete mode 100644 drivers/net/wireless/bcm43xx/COPYING (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/COPYING b/drivers/net/wireless/bcm43xx/COPYING deleted file mode 100644 index 5b6e7c66c27..00000000000 --- a/drivers/net/wireless/bcm43xx/COPYING +++ /dev/null @@ -1,340 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 - - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Library General -Public License instead of this License. -- cgit v1.2.3 From 6f3e2045cabd952a86bc819181d8a190cd0689c3 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 30 Jan 2006 17:43:20 +0100 Subject: [PATCH] bcm43xx: add DEBUG Kconfig option. Also fix indention. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 7c7dca112bf..3b1363c9719 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -502,12 +502,21 @@ config PRISM54 source "drivers/net/wireless/hostap/Kconfig" config BCM43XX - tristate "Broadcom BCM43xx wireless support" - depends on PCI && IEEE80211 && NET_RADIO && IEEE80211_SOFTMAC && EXPERIMENTAL + tristate "Broadcom BCM43xx wireless support" + depends on PCI && IEEE80211 && NET_RADIO && IEEE80211_SOFTMAC && EXPERIMENTAL select FW_LOADER - ---help--- - This is an experimental driver for the Broadcom 43xx wireless chip, - found in the Apple Airport Extreme and various other devices. + ---help--- + This is an experimental driver for the Broadcom 43xx wireless chip, + found in the Apple Airport Extreme and various other devices. + +config BCM43XX_DEBUG + bool "Broadcom BCM43xx debugging (RECOMMENDED)" + depends on BCM43XX + default y + ---help--- + Broadcom 43xx debugging messages. + Say Y, because the driver is still very experimental and + this will help you get it running. # yes, this works even when no drivers are selected config NET_WIRELESS -- cgit v1.2.3 From 65f3f19120cf32233f537562e69893b88727b634 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 31 Jan 2006 20:11:38 +0100 Subject: [PATCH] bcm43xx: Fix makefile. Remove all the "out-of-tree" stuff. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/Makefile | 87 ++------------------------ drivers/net/wireless/bcm43xx/bcm43xx.h | 6 +- drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 8 +-- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 11 ++-- 4 files changed, 14 insertions(+), 98 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile index 98d4efb1d12..3e5ed77835e 100644 --- a/drivers/net/wireless/bcm43xx/Makefile +++ b/drivers/net/wireless/bcm43xx/Makefile @@ -1,87 +1,8 @@ -# Makefile for bcm43xx driver +obj-$(CONFIG_BCM43XX) += bcm43xx.o +bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.o -VERSION := 0.0.1 -RELEASE_NAME := bcm43xx-$(VERSION) - -# Optional path, where the SoftMAC subsystem is located. -# You may set SOFTMAC_DIR in your bashrc, for example. -SOFTMAC_DIR ?= - -KVER := $(shell uname -r) -KDIR ?= /lib/modules/$(KVER)/build -PWD := $(shell pwd) -MODPATH := $(DESTDIR)/lib/modules/$(KVER)/kernel/drivers/net/bcm43xx - -# Comment/uncomment to enable/disable debugging -DEBUG = y - - -ifeq ($(DEBUG),y) -DEBUGFS_OBJ = bcm43xx_debugfs.o -CFLAGS += -O2 -DCONFIG_BCM43XX_DEBUG -else -DEBUGFS_OBJ = -CFLAGS += -O2 -endif - -CFLAGS += -DBCM43xx_VERSION=$(VERSION) -I/lib/modules/$(KVER)/include -ifneq ($(SOFTMAC_DIR),) -CPPFLAGS := -I$(SOFTMAC_DIR) $(CPPFLAGS) -endif - -ifneq ($(KERNELRELEASE),) -# call from kernel build system - -obj-m := bcm43xx.o -bcm43xx-objs := bcm43xx_main.o bcm43xx_dma.o $(DEBUGFS_OBJ) \ +bcm43xx-objs := bcm43xx_main.o bcm43xx_dma.o \ bcm43xx_radio.o bcm43xx_phy.o \ bcm43xx_power.o bcm43xx_wx.o \ bcm43xx_pio.o bcm43xx_ilt.o \ - bcm43xx_leds.o - -else - -default: modules - -modules: - $(MAKE) -C $(KDIR) M=$(PWD) modules - -install: bcm43xx.ko - install -d $(MODPATH) - install -m 644 -c bcm43xx.ko $(MODPATH) - /sbin/depmod -a - -uninstall: - rm -rf $(MODPATH) - /sbin/depmod -a - -endif - -clean: - find . \( -name '*.ko' -o -name '*.o' -o -name '.tmp_versions' -o -name '*~' -o -name '.*.cmd' \ - -o -name '*.mod.c' -o -name '*.tar.bz2' -o -name '*.rej' -o -name '*.orig' \)\ - -print | xargs rm -Rf - -depend .depend dep: - $(CC) $(CFLAGS) -M *.c > .depend - -ifeq (.depend,$(wildcard .depend)) -include .depend -endif - -DISTFILES = $(shell find . \( -not -name '.' \) -print | grep -v "\.tar\.bz2" | grep -v "\/\." ) -DISTDIR = $(RELEASE_NAME) - -release: clean - @rm -rf $(DISTDIR) - @mkdir $(DISTDIR) - @chmod 777 $(DISTDIR) - @for file in $(DISTFILES); do \ - if test -d $$file; then \ - mkdir $(DISTDIR)/$$file; \ - else \ - cp -p $$file $(DISTDIR)/$$file; \ - fi; \ - done - @tar -c $(DISTDIR) | bzip2 -9 > $(RELEASE_NAME).tar.bz2 - @rm -rf $(DISTDIR) + bcm43xx_leds.o $(bcm43xx-obj-y) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 38e75ed2b65..7b97d8bf79e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -17,14 +17,10 @@ #include "bcm43xx_leds.h" -#define DRV_NAME __stringify(KBUILD_MODNAME) -#define DRV_VERSION __stringify(BCM43xx_VERSION) -#define BCM43xx_DRIVER_NAME DRV_NAME " driver " DRV_VERSION -#define PFX DRV_NAME ": " +#define PFX KBUILD_MODNAME ": " #define BCM43xx_SWITCH_CORE_MAX_RETRIES 10 #define BCM43xx_IRQWAIT_MAX_RETRIES 50 -#define BCM43xx_TX_TIMEOUT (10 * HZ) #define BCM43xx_IO_SIZE 8192 #define BCM43xx_REG_ACTIVE_CORE 0x80 diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index f8cfc84ca0d..5a7dc43cd67 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -141,7 +141,7 @@ static ssize_t drvinfo_read_file(struct file *file, char __user *userbuf, down(&big_buffer_sem); /* This is where the information is written to the "driver" file */ - fappend(BCM43xx_DRIVER_NAME "\n"); + fappend(KBUILD_MODNAME " driver\n"); fappend("Compiled at: %s %s\n", __DATE__, __TIME__); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); @@ -433,12 +433,12 @@ void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, void bcm43xx_debugfs_init(void) { memset(&fs, 0, sizeof(fs)); - fs.root = debugfs_create_dir(DRV_NAME, NULL); + fs.root = debugfs_create_dir(KBUILD_MODNAME, NULL); if (!fs.root) - printk(KERN_ERR PFX "debugfs: creating \"" DRV_NAME "\" subdir failed!\n"); + printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "\" subdir failed!\n"); fs.dentry_driverinfo = debugfs_create_file("driver", 0444, fs.root, NULL, &drvinfo_fops); if (!fs.dentry_driverinfo) - printk(KERN_ERR PFX "debugfs: creating \"" DRV_NAME "/driver\" failed!\n"); + printk(KERN_ERR PFX "debugfs: creating \"" KBUILD_MODNAME "/driver\" failed!\n"); } void bcm43xx_debugfs_exit(void) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 4b4e60a22c0..cfb0f0a485a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2471,7 +2471,7 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) } #endif res = request_irq(bcm->irq, bcm43xx_interrupt_handler, - SA_SHIRQ, DRV_NAME, bcm); + SA_SHIRQ, KBUILD_MODNAME, bcm); if (res) { printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); return -EFAULT; @@ -3809,7 +3809,7 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) } #endif - err = pci_request_regions(pci_dev, DRV_NAME); + err = pci_request_regions(pci_dev, KBUILD_MODNAME); if (err) { printk(KERN_ERR PFX "could not access PCI resources (%i)\n", err); @@ -4389,12 +4389,11 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, #endif net_dev->wireless_handlers = &bcm43xx_wx_handlers_def; net_dev->irq = pdev->irq; - net_dev->watchdog_timeo = BCM43xx_TX_TIMEOUT; /* initialize the bcm43xx_private struct */ bcm = bcm43xx_priv(net_dev); memset(bcm, 0, sizeof(*bcm)); - wq = create_workqueue(DRV_NAME "_wq"); + wq = create_workqueue(KBUILD_MODNAME "_wq"); if (!wq) { err = -ENOMEM; goto err_free_netdev; @@ -4567,7 +4566,7 @@ static int bcm43xx_resume(struct pci_dev *pdev) #endif /* CONFIG_PM */ static struct pci_driver bcm43xx_pci_driver = { - .name = BCM43xx_DRIVER_NAME, + .name = KBUILD_MODNAME, .id_table = bcm43xx_pci_tbl, .probe = bcm43xx_init_one, .remove = __devexit_p(bcm43xx_remove_one), @@ -4579,7 +4578,7 @@ static struct pci_driver bcm43xx_pci_driver = { static int __init bcm43xx_init(void) { - printk(KERN_INFO BCM43xx_DRIVER_NAME "\n"); + printk(KERN_INFO KBUILD_MODNAME " driver\n"); bcm43xx_debugfs_init(); return pci_register_driver(&bcm43xx_pci_driver); } -- cgit v1.2.3 From a4a600d3e17f450666a9086465122103e96140d7 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 1 Feb 2006 22:09:52 +0100 Subject: [PATCH] bcm43xx: Add more initvals sanity checks and error out, if one sanity check fails. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 62 ++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 19 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index cfb0f0a485a..521777f56a3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2229,9 +2229,9 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re return IRQ_HANDLED; } -static void bcm43xx_release_firmware(struct bcm43xx_private *bcm) +static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) { - if (bcm->firmware_norelease) + if (bcm->firmware_norelease && !force) return; /* Suspending or controller reset. */ release_firmware(bcm->ucode); bcm->ucode = NULL; @@ -2361,7 +2361,7 @@ static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) out: return err; error: - bcm43xx_release_firmware(bcm); + bcm43xx_release_firmware(bcm, 1); goto out; err_noinitval: printk(KERN_ERR PFX "Error: No InitVals available!\n"); @@ -2409,9 +2409,9 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) #endif } -static void bcm43xx_write_initvals(struct bcm43xx_private *bcm, - const struct bcm43xx_initval *data, - const unsigned int len) +static int bcm43xx_write_initvals(struct bcm43xx_private *bcm, + const struct bcm43xx_initval *data, + const unsigned int len) { u16 offset, size; u32 value; @@ -2422,35 +2422,54 @@ static void bcm43xx_write_initvals(struct bcm43xx_private *bcm, size = be16_to_cpu(data[i].size); value = be32_to_cpu(data[i].value); - if (size == 2) - bcm43xx_write16(bcm, offset, value); - else if (size == 4) + if (unlikely(offset >= 0x1000)) + goto err_format; + if (size == 2) { + if (unlikely(value & 0xFFFF0000)) + goto err_format; + bcm43xx_write16(bcm, offset, (u16)value); + } else if (size == 4) { bcm43xx_write32(bcm, offset, value); - else - printk(KERN_ERR PFX "InitVals fileformat error.\n"); + } else + goto err_format; } + + return 0; + +err_format: + printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. " + "Please fix your bcm43xx firmware files.\n"); + return -EPROTO; } -static void bcm43xx_upload_initvals(struct bcm43xx_private *bcm) +static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) { + int err; + #ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT bcm43xx_mmioprint_enable(bcm); #else bcm43xx_mmioprint_disable(bcm); #endif - bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, - bcm->initvals0->size / sizeof(struct bcm43xx_initval)); + err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, + bcm->initvals0->size / sizeof(struct bcm43xx_initval)); + if (err) + goto out; if (bcm->initvals1) { - bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, - bcm->initvals1->size / sizeof(struct bcm43xx_initval)); + err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, + bcm->initvals1->size / sizeof(struct bcm43xx_initval)); + if (err) + goto out; } +out: #ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT bcm43xx_mmioprint_disable(bcm); #else bcm43xx_mmioprint_enable(bcm); #endif + return err; } static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) @@ -2683,7 +2702,7 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm) bcm43xx_leds_exit(bcm); bcm43xx_gpio_cleanup(bcm); free_irq(bcm->irq, bcm); - bcm43xx_release_firmware(bcm); + bcm43xx_release_firmware(bcm, 0); } /* Initialize the chip @@ -2708,13 +2727,15 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) err = bcm43xx_initialize_irq(bcm); if (err) - goto out; + goto err_release_fw; err = bcm43xx_gpio_init(bcm); if (err) goto err_free_irq; - bcm43xx_upload_initvals(bcm); + err = bcm43xx_upload_initvals(bcm); + if (err) + goto err_gpio_cleanup; bcm43xx_radio_turn_on(bcm); if (modparam_noleds) @@ -2813,9 +2834,12 @@ out: err_radio_off: bcm43xx_radio_turn_off(bcm); +err_gpio_cleanup: bcm43xx_gpio_cleanup(bcm); err_free_irq: free_irq(bcm->irq, bcm); +err_release_fw: + bcm43xx_release_firmware(bcm, 1); goto out; } -- cgit v1.2.3 From 9e4a375b15c9940b13e66e224570b35c471c0128 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 2 Feb 2006 18:43:25 +0100 Subject: [PATCH] bcm43xx: Remove function bcm43xx_channel_is_allowed() Geographical restriction should become part of the 80211 stack, so every driver does not have to duplicate it. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 166 +--------------------------- 1 file changed, 1 insertion(+), 165 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 521777f56a3..c0ec503102c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -82,10 +82,6 @@ static int modparam_locale = -1; module_param_named(locale, modparam_locale, int, 0444); MODULE_PARM_DESC(country, "Select LocaleCode 0-11 (For travelers)"); -static int modparam_outdoor; -module_param_named(outdoor, modparam_outdoor, int, 0444); -MODULE_PARM_DESC(outdoor, "Set to 1, if you are using the device outdoor, 0 otherwise."); - static int modparam_noleds; module_param_named(noleds, modparam_noleds, int, 0444); MODULE_PARM_DESC(noleds, "Turn off all LED activity"); @@ -1088,163 +1084,13 @@ static int bcm43xx_read_sprom(struct bcm43xx_private *bcm) return 0; } -static int bcm43xx_channel_is_allowed(struct bcm43xx_private *bcm, u8 channel, - u8 *max_power, u8 *flags) -{ - /* THIS FUNCTION DOES _NOT_ ENFORCE REGULATORY DOMAIN COMPLIANCE. - * It is only a helper function to make life easier to - * select legal channels and transmission powers. - */ - - u8 phytype = bcm->current_core->phy->type; - int allowed = 0; - - *max_power = 0; - *flags = 0; - - //FIXME: Set max_power and maybe flags - /*FIXME: Allowed channels are sometimes different for outdoor - * or indoor use. See modparam_outdoor. - */ - /* From b specs Max Power BPHY: - * USA: 1000mW - * Europe: 100mW - * Japan: 10mW/MHz - */ - - switch (bcm->sprom.locale) { - case BCM43xx_LOCALE_WORLD: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 1 && channel <= 13) - allowed = 1; - } else { - if (channel >= 1 && channel <= 13) - allowed = 1; - } - break; - case BCM43xx_LOCALE_THAILAND: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 1 && channel <= 14) - allowed = 1; - } else { - if (channel >= 1 && channel <= 14) - allowed = 1; - } - break; - case BCM43xx_LOCALE_ISRAEL: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 5 && channel <= 7) - allowed = 1; - } else { - if (channel >= 5 && channel <= 7) - allowed = 1; - } - break; - case BCM43xx_LOCALE_JORDAN: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 10 && channel <= 13) - allowed = 1; - } else { - if (channel >= 10 && channel <= 13) - allowed = 1; - } - break; - case BCM43xx_LOCALE_CHINA: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 1 && channel <= 13) - allowed = 1; - } else { - if (channel >= 1 && channel <= 13) - allowed = 1; - } - break; - case BCM43xx_LOCALE_JAPAN: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - //FIXME: This seems to be wrong. - if (channel >= 1 && channel <= 14) - allowed = 1; - } else { - //FIXME: This seems to be wrong. - if (channel >= 1 && channel <= 14) - allowed = 1; - } - break; - case BCM43xx_LOCALE_USA_CANADA_ANZ: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 1 && channel <= 13) - allowed = 1; - } else { - if (channel >= 1 && channel <= 11) - allowed = 1; - } - break; - case BCM43xx_LOCALE_EUROPE: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 1 && channel <= 13) - allowed = 1; - } else { - if (channel >= 1 && channel <= 13) - allowed = 1; - } - break; - case BCM43xx_LOCALE_USA_LOW: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - if (channel >= 1 && channel <= 13) - allowed = 1; - } else { - if (channel >= 1 && channel <= 11) - allowed = 1; - } - break; - case BCM43xx_LOCALE_JAPAN_HIGH: - if (phytype == BCM43xx_PHYTYPE_A) { - allowed = 1;//FIXME - } else if (phytype == BCM43xx_PHYTYPE_B) { - //FIXME? - if (channel >= 1 && channel <= 14) - allowed = 1; - } else { - if (channel >= 1 && channel <= 14) - allowed = 1; - } - break; - case BCM43xx_LOCALE_ALL: - allowed = 1; - break; - case BCM43xx_LOCALE_NONE: - break; - default: - assert(0); - } - - return allowed; -} - static void bcm43xx_geo_init(struct bcm43xx_private *bcm) { struct ieee80211_geo geo; struct ieee80211_channel *chan; int have_a = 0, have_bg = 0; int i, num80211; - u8 channel, flags, max_power; + u8 channel; struct bcm43xx_phyinfo *phy; const char *iso_country; @@ -1268,27 +1114,17 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) if (have_a) { for (i = 0, channel = 0; channel < 201; channel++) { - if (!bcm43xx_channel_is_allowed(bcm, channel, - &max_power, &flags)) - continue; chan = &geo.a[i++]; chan->freq = bcm43xx_channel_to_freq(bcm, channel); chan->channel = channel; - chan->flags = flags; - chan->max_power = max_power; } geo.a_channels = i; } if (have_bg) { for (i = 0, channel = 1; channel < 15; channel++) { - if (!bcm43xx_channel_is_allowed(bcm, channel, - &max_power, &flags)) - continue; chan = &geo.bg[i++]; chan->freq = bcm43xx_channel_to_freq(bcm, channel); chan->channel = channel; - chan->flags = flags; - chan->max_power = max_power; } geo.bg_channels = i; } -- cgit v1.2.3 From 6465ce1bbf7fede82dccec342417105b10793b51 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 2 Feb 2006 19:11:08 +0100 Subject: [PATCH] bcm43xx: basic ethtool support This patch contains the beginnings of ethtool support for bcm43xx. It only implements get_drvinfo and get_link, but that's enough for ifplugd to use ethtool to know whether we're associated or not and then start or stop dhcp as necessary. Signed-off-by: Jason Lunz Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/Makefile | 3 +- drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c | 50 ++++++++++++++++++++++++++ drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h | 8 +++++ drivers/net/wireless/bcm43xx/bcm43xx_main.c | 2 ++ 4 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile index 3e5ed77835e..e025e9f052b 100644 --- a/drivers/net/wireless/bcm43xx/Makefile +++ b/drivers/net/wireless/bcm43xx/Makefile @@ -5,4 +5,5 @@ bcm43xx-objs := bcm43xx_main.o bcm43xx_dma.o \ bcm43xx_radio.o bcm43xx_phy.o \ bcm43xx_power.o bcm43xx_wx.o \ bcm43xx_pio.o bcm43xx_ilt.o \ - bcm43xx_leds.o $(bcm43xx-obj-y) + bcm43xx_leds.o bcm43xx_ethtool.o \ + $(bcm43xx-obj-y) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c new file mode 100644 index 00000000000..b3ffcf50131 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c @@ -0,0 +1,50 @@ +/* + + Broadcom BCM43xx wireless driver + + ethtool support + + Copyright (c) 2006 Jason Lunz + + Some code in this file is derived from the 8139too.c driver + Copyright (C) 2002 Jeff Garzik + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx.h" +#include "bcm43xx_ethtool.h" + +#include +#include +#include +#include + + +static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(dev); + + strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); + strncpy(info->version, UTS_RELEASE, sizeof(info->version)); + strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN); +} + +struct ethtool_ops bcm43xx_ethtool_ops = { + .get_drvinfo = bcm43xx_get_drvinfo, + .get_link = ethtool_op_get_link, +}; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h new file mode 100644 index 00000000000..813704991f6 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.h @@ -0,0 +1,8 @@ +#ifndef BCM43xx_ETHTOOL_H_ +#define BCM43xx_ETHTOOL_H_ + +#include + +extern struct ethtool_ops bcm43xx_ethtool_ops; + +#endif /* BCM43xx_ETHTOOL_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index c0ec503102c..1051a49ddaf 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -49,6 +49,7 @@ #include "bcm43xx_pio.h" #include "bcm43xx_power.h" #include "bcm43xx_wx.h" +#include "bcm43xx_ethtool.h" MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); @@ -4249,6 +4250,7 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, #endif net_dev->wireless_handlers = &bcm43xx_wx_handlers_def; net_dev->irq = pdev->irq; + SET_ETHTOOL_OPS(net_dev, &bcm43xx_ethtool_ops); /* initialize the bcm43xx_private struct */ bcm = bcm43xx_priv(net_dev); -- cgit v1.2.3 From 8fa252d099d864f8848a9890f26d1a51a9c7ad32 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 2 Feb 2006 19:49:15 +0100 Subject: [PATCH] bcm43xx: Wireless Ext update Wireless Ext update: update we_version_source set enc_capa Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index fe6409a9090..c1d788d50f4 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -41,6 +41,11 @@ #include "bcm43xx_main.h" #include "bcm43xx_radio.h" + +/* The WIRELESS_EXT version, which is implemented by this driver. */ +#define BCM43xx_WX_VERSION 18 + + /* Define to enable a printk on each wx handler function invocation */ //#define BCM43xx_WX_DEBUG @@ -282,7 +287,12 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, range->max_encoding_tokens = WEP_KEYS; range->we_version_compiled = WIRELESS_EXT; - range->we_version_source = 16; + range->we_version_source = BCM43xx_WX_VERSION; + + range->enc_capa = IW_ENC_CAPA_WPA | + IW_ENC_CAPA_WPA2 | + IW_ENC_CAPA_CIPHER_TKIP | + IW_ENC_CAPA_CIPHER_CCMP; spin_lock_irqsave(&bcm->lock, flags); -- cgit v1.2.3 From 67093a65c08dc45374f642b1ec1b86e7095a4dc8 Mon Sep 17 00:00:00 2001 From: Danny van Dyk Date: Wed, 1 Feb 2006 00:43:05 +0100 Subject: [PATCH] Sync bcm43xx_phy_initb6() with specs Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 15 ++++++++++----- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_radio.h | 1 + 3 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index f5e7a6ab93c..d90f207b247 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -947,7 +947,7 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) bcm43xx_radio_write16(bcm, 0x0050, 0x0020); if ((bcm->current_core->radio->manufact == 0x17F) && (bcm->current_core->radio->version == 0x2050) && - (bcm->current_core->radio->revision == 2)) { + (bcm->current_core->radio->revision <= 2)) { bcm43xx_radio_write16(bcm, 0x0050, 0x0020); bcm43xx_radio_write16(bcm, 0x005A, 0x0070); bcm43xx_radio_write16(bcm, 0x005B, 0x007B); @@ -984,10 +984,15 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) bcm43xx_write16(bcm, 0x03E4, 0x0009); if (phy->type == BCM43xx_PHYTYPE_B) { bcm43xx_write16(bcm, 0x03E6, 0x8140); - bcm43xx_phy_write(bcm, 0x0016, 0x5410); - bcm43xx_phy_write(bcm, 0x0017, 0xA820); - bcm43xx_phy_write(bcm, 0x0007, 0x0062); - TODO();//TODO: calibrate stuff. + bcm43xx_phy_write(bcm, 0x0016, 0x0410); + bcm43xx_phy_write(bcm, 0x0017, 0x0820); + bcm43xx_phy_write(bcm, 0x0062, 0x0007); + (void) bcm43xx_radio_calibrationvalue(bcm); + bcm43xx_phy_lo_b_measure(bcm); + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + bcm43xx_calc_nrssi_slope(bcm); + bcm43xx_calc_nrssi_threshold(bcm); + } bcm43xx_phy_init_pctl(bcm); } else bcm43xx_write16(bcm, 0x03E6, 0x0); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 5ce6acef2c4..3901aa99466 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -1184,7 +1184,7 @@ int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, return 0; } -static u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm) +u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm) { u16 reg, index, ret; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h index 89fe2928214..a5d2e10d5d9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h @@ -89,5 +89,6 @@ void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val); void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm); void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm); +u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm); #endif /* BCM43xx_RADIO_H_ */ -- cgit v1.2.3 From 393344f67b598aaed594b9006e9eaa44ab62caa0 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 5 Feb 2006 15:28:20 +0100 Subject: [PATCH] bcm43xx: fix txpower reporting in WE. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 2 ++ drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 +++ drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 9 ++---- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 44 +++++++++++++++++++++++------ 4 files changed, 44 insertions(+), 15 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 7b97d8bf79e..981d563f573 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -525,6 +525,8 @@ struct bcm43xx_radioinfo { * 3: tx_CTL2 */ u16 txpower[4]; + /* Desired TX power in dBm Q5.2 */ + u16 txpower_desired; /* Current Interference Mitigation mode */ int interfmode; /* Stack of saved values from the Interference Mitigation code */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 1051a49ddaf..8e08c41f86d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -793,6 +793,10 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) bcm->current_core->radio->txpower[2] = 3; else bcm->current_core->radio->txpower[2] = 0; + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + bcm->current_core->radio->txpower_desired = bcm->sprom.maxpower_aphy; + else + bcm->current_core->radio->txpower_desired = bcm->sprom.maxpower_bgphy; /* Initialize the in-memory nrssi Lookup Table. */ for (i = 0; i < 64; i++) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index d90f207b247..d3c2fc1df37 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -1768,14 +1768,9 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) where REG is the max power as per the regulatory domain */ - /*TODO: Get desired_pwr from wx_handlers or the stack - limit_value(desired_pwr, 0, max_pwr); - */ - - desired_pwr = max_pwr; /* remove this when we have a real desired_pwr */ - + desired_pwr = limit_value(radio->txpower_desired, 0, max_pwr); + /* Check if we need to adjust the current power. */ pwr_adjust = desired_pwr - estimated_pwr; - radio_att_delta = -(pwr_adjust + 7) >> 3; baseband_att_delta = -(pwr_adjust >> 1) - (4 * radio_att_delta); if ((radio_att_delta == 0) && (baseband_att_delta == 0)) { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index c1d788d50f4..bed7cfbe81d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -484,21 +484,40 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct bcm43xx_radioinfo *radio; + struct bcm43xx_phyinfo *phy; unsigned long flags; int err = -ENODEV; + u16 maxpower; wx_enter(); + if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { + printk(PFX KERN_ERR "TX power not in dBm.\n"); + return -EOPNOTSUPP; + } + spin_lock_irqsave(&bcm->lock, flags); if (!bcm->initialized) goto out_unlock; - if (data->power.disabled != (!(bcm->current_core->radio->enabled))) { - if (data->power.disabled) + radio = bcm->current_core->radio; + phy = bcm->current_core->phy; + if (data->txpower.disabled != (!(radio->enabled))) { + if (data->txpower.disabled) bcm43xx_radio_turn_off(bcm); else bcm43xx_radio_turn_on(bcm); } - //TODO: set txpower. + if (data->txpower.value > 0) { + /* desired and maxpower dBm values are in Q5.2 */ + if (phy->type == BCM43xx_PHYTYPE_A) + maxpower = bcm->sprom.maxpower_aphy; + else + maxpower = bcm->sprom.maxpower_bgphy; + radio->txpower_desired = limit_value(data->txpower.value << 2, + 0, maxpower); + bcm43xx_phy_xmitpower(bcm); + } err = 0; out_unlock: @@ -513,18 +532,27 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct bcm43xx_radioinfo *radio; unsigned long flags; + int err = -ENODEV; wx_enter(); spin_lock_irqsave(&bcm->lock, flags); -//TODO data->power.value = ??? - data->power.fixed = 1; - data->power.flags = IW_TXPOW_DBM; - data->power.disabled = !(bcm->current_core->radio->enabled); + if (!bcm->initialized) + goto out_unlock; + radio = bcm->current_core->radio; + /* desired dBm value is in Q5.2 */ + data->txpower.value = radio->txpower_desired >> 2; + data->txpower.fixed = 1; + data->txpower.flags = IW_TXPOW_DBM; + data->txpower.disabled = !(radio->enabled); + + err = 0; +out_unlock: spin_unlock_irqrestore(&bcm->lock, flags); - return 0; + return err; } static int bcm43xx_wx_set_retry(struct net_device *net_dev, -- cgit v1.2.3 From 62b7f0dfab0508a45a93045d49eda26d5285188d Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 8 Feb 2006 17:36:46 +0100 Subject: [PATCH] bcm43xx: enable SPROM writing. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index bed7cfbe81d..6f6f19aed30 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -976,7 +976,7 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev, printk("75%%"); else if (i % 2) printk("."); -//TODO bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); + bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); mdelay(20); } spromctl &= ~0x10; /* SPROM WRITE enable. */ -- cgit v1.2.3 From 921e485f98b11656cdcc39a37605e116e34cb315 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 8 Feb 2006 17:55:55 +0100 Subject: [PATCH] bcm43xx: heavily increase mac_suspend timeout. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 8e08c41f86d..4c4a2d71ca0 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2473,16 +2473,13 @@ void bcm43xx_mac_suspend(struct bcm43xx_private *bcm) bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) & ~BCM43xx_SBF_MAC_ENABLED); bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ - for (i = 1000; i > 0; i--) { + for (i = 100000; i; i--) { tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); - if (tmp & BCM43xx_IRQ_READY) { - i = -1; - break; - } + if (tmp & BCM43xx_IRQ_READY) + return; udelay(10); } - if (!i) - printkl(KERN_ERR PFX "Failed to suspend mac!\n"); + printkl(KERN_ERR PFX "MAC suspend failed\n"); } void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, -- cgit v1.2.3 From b5488beba8030b791e035c4da0122f98c42e355b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 8 Feb 2006 18:00:30 +0100 Subject: [PATCH] bcm43xx: fix compiletime warning (phy_xmitpower) Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 6f6f19aed30..d383337db99 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -40,6 +40,7 @@ #include "bcm43xx_wx.h" #include "bcm43xx_main.h" #include "bcm43xx_radio.h" +#include "bcm43xx_phy.h" /* The WIRELESS_EXT version, which is implemented by this driver. */ -- cgit v1.2.3 From 5c57807afcc28a6b8fb579ef2c79e49f0b688425 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 8 Feb 2006 18:04:02 +0100 Subject: [PATCH] bcm43xx: remove WX debugging. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 68 ------------------------------- 1 file changed, 68 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index d383337db99..4c972cdc0a2 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -46,18 +46,6 @@ /* The WIRELESS_EXT version, which is implemented by this driver. */ #define BCM43xx_WX_VERSION 18 - -/* Define to enable a printk on each wx handler function invocation */ -//#define BCM43xx_WX_DEBUG - - -#ifdef BCM43xx_WX_DEBUG -# define printk_wx printk -#else -# define printk_wx(x...) do { /* nothing */ } while (0) -#endif -#define wx_enter() printk_wx(KERN_INFO PFX "WX handler called: %s\n", __FUNCTION__); - #define MAX_WX_STRING 80 @@ -73,8 +61,6 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, char suffix[7] = { 0 }; int have_a = 0, have_b = 0, have_g = 0; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); nr_80211 = bcm43xx_num_80211_cores(bcm); for (i = 0; i < nr_80211; i++) { @@ -127,8 +113,6 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, int freq; int err = 0; - wx_enter(); - if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { channel = data->freq.m; freq = bcm43xx_channel_to_freq(bcm, channel); @@ -148,8 +132,6 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, } else bcm->current_core->radio->initial_channel = channel; spin_unlock_irqrestore(&bcm->lock, flags); - if (!err) - printk_wx(KERN_INFO PFX "Selected channel: %d\n", channel); return err; } @@ -164,8 +146,6 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, int err = -ENODEV; u16 channel; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); channel = bcm->current_core->radio->channel; if (channel == 0xFF) { @@ -195,8 +175,6 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev, unsigned long flags; int mode; - wx_enter(); - mode = data->mode; if (mode == IW_MODE_AUTO) mode = BCM43xx_INITIAL_IWMODE; @@ -217,8 +195,6 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); data->mode = bcm->ieee->iw_mode; spin_unlock_irqrestore(&bcm->lock, flags); @@ -231,7 +207,6 @@ static int bcm43xx_wx_set_sensitivity(struct net_device *net_dev, union iwreq_data *data, char *extra) { - wx_enter(); /*TODO*/ return 0; } @@ -241,7 +216,6 @@ static int bcm43xx_wx_get_sensitivity(struct net_device *net_dev, union iwreq_data *data, char *extra) { - wx_enter(); /*TODO*/ return 0; } @@ -257,8 +231,6 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, unsigned long flags; int i, j; - wx_enter(); - data->data.length = sizeof(*range); memset(range, 0, sizeof(*range)); @@ -355,8 +327,6 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev, unsigned long flags; size_t len; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); memcpy(bcm->nick, extra, len); @@ -375,8 +345,6 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev, unsigned long flags; size_t len; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); len = strlen(bcm->nick) + 1; memcpy(extra, bcm->nick, len); @@ -396,8 +364,6 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, unsigned long flags; int err = -EINVAL; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); if (data->rts.disabled) { bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; @@ -422,8 +388,6 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); data->rts.value = bcm->rts_threshold; data->rts.fixed = 0; @@ -442,8 +406,6 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, unsigned long flags; int err = -EINVAL; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); if (data->frag.disabled) { bcm->ieee->fts = MAX_FRAG_THRESHOLD; @@ -468,8 +430,6 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); data->frag.value = bcm->ieee->fts; data->frag.fixed = 0; @@ -491,8 +451,6 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, int err = -ENODEV; u16 maxpower; - wx_enter(); - if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) { printk(PFX KERN_ERR "TX power not in dBm.\n"); return -EOPNOTSUPP; @@ -537,8 +495,6 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, unsigned long flags; int err = -ENODEV; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); if (!bcm->initialized) goto out_unlock; @@ -561,7 +517,6 @@ static int bcm43xx_wx_set_retry(struct net_device *net_dev, union iwreq_data *data, char *extra) { - wx_enter(); /*TODO*/ return 0; } @@ -571,7 +526,6 @@ static int bcm43xx_wx_get_retry(struct net_device *net_dev, union iwreq_data *data, char *extra) { - wx_enter(); /*TODO*/ return 0; } @@ -584,8 +538,6 @@ static int bcm43xx_wx_set_encoding(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); int err; - wx_enter(); - err = ieee80211_wx_set_encode(bcm->ieee, info, data, extra); return err; @@ -599,8 +551,6 @@ static int bcm43xx_wx_set_encodingext(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); int err; - wx_enter(); - err = ieee80211_wx_set_encodeext(bcm->ieee, info, data, extra); return err; @@ -614,8 +564,6 @@ static int bcm43xx_wx_get_encoding(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); int err; - wx_enter(); - err = ieee80211_wx_get_encode(bcm->ieee, info, data, extra); return err; @@ -629,8 +577,6 @@ static int bcm43xx_wx_get_encodingext(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); int err; - wx_enter(); - err = ieee80211_wx_get_encodeext(bcm->ieee, info, data, extra); return err; @@ -641,7 +587,6 @@ static int bcm43xx_wx_set_power(struct net_device *net_dev, union iwreq_data *data, char *extra) { - wx_enter(); /*TODO*/ return 0; } @@ -651,7 +596,6 @@ static int bcm43xx_wx_get_power(struct net_device *net_dev, union iwreq_data *data, char *extra) { - wx_enter(); /*TODO*/ return 0; } @@ -665,8 +609,6 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, unsigned long flags; int mode, err = 0; - wx_enter(); - mode = *((int *)extra); switch (mode) { case 0: @@ -717,8 +659,6 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, unsigned long flags; int mode; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); mode = bcm->current_core->radio->interfmode; spin_unlock_irqrestore(&bcm->lock, flags); @@ -750,8 +690,6 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, unsigned long flags; int on; - wx_enter(); - on = *((int *)extra); spin_lock_irqsave(&bcm->lock, flags); bcm->short_preamble = !!on; @@ -769,8 +707,6 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, unsigned long flags; int on; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); on = bcm->short_preamble; spin_unlock_irqrestore(&bcm->lock, flags); @@ -793,8 +729,6 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, unsigned long flags; int on; - wx_enter(); - on = *((int *)extra); spin_lock_irqsave(&bcm->lock, flags); bcm->ieee->host_encrypt = !!on; @@ -815,8 +749,6 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, unsigned long flags; int on; - wx_enter(); - spin_lock_irqsave(&bcm->lock, flags); on = bcm->ieee->host_encrypt; spin_unlock_irqrestore(&bcm->lock, flags); -- cgit v1.2.3 From 77db31ea4322f2dd12dc814d6664ae96517604c0 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 12 Feb 2006 16:47:44 +0100 Subject: [PATCH] bcm43xx: Partially fix PIO code. Add Kconfig option for PIO or DMA mode (or both). Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 18 +- drivers/net/wireless/bcm43xx/Kconfig | 57 +++++ drivers/net/wireless/bcm43xx/Makefile | 6 +- drivers/net/wireless/bcm43xx/bcm43xx.h | 29 ++- drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 46 ++++ drivers/net/wireless/bcm43xx/bcm43xx_main.c | 69 +++-- drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 383 ++++++++++++++-------------- drivers/net/wireless/bcm43xx/bcm43xx_pio.h | 78 +++++- 8 files changed, 438 insertions(+), 248 deletions(-) create mode 100644 drivers/net/wireless/bcm43xx/Kconfig (limited to 'drivers/net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 3b1363c9719..5c4d7b4ece5 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -500,23 +500,7 @@ config PRISM54 will be called prism54.ko. source "drivers/net/wireless/hostap/Kconfig" - -config BCM43XX - tristate "Broadcom BCM43xx wireless support" - depends on PCI && IEEE80211 && NET_RADIO && IEEE80211_SOFTMAC && EXPERIMENTAL - select FW_LOADER - ---help--- - This is an experimental driver for the Broadcom 43xx wireless chip, - found in the Apple Airport Extreme and various other devices. - -config BCM43XX_DEBUG - bool "Broadcom BCM43xx debugging (RECOMMENDED)" - depends on BCM43XX - default y - ---help--- - Broadcom 43xx debugging messages. - Say Y, because the driver is still very experimental and - this will help you get it running. +source "drivers/net/wireless/bcm43xx/Kconfig" # yes, this works even when no drivers are selected config NET_WIRELESS diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig new file mode 100644 index 00000000000..d8d23155ee3 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/Kconfig @@ -0,0 +1,57 @@ +config BCM43XX + tristate "Broadcom BCM43xx wireless support" + depends on PCI && IEEE80211 && IEEE80211_SOFTMAC && NET_RADIO && EXPERIMENTAL + select FW_LOADER + ---help--- + This is an experimental driver for the Broadcom 43xx wireless chip, + found in the Apple Airport Extreme and various other devices. + +config BCM43XX_DEBUG + bool "Broadcom BCM43xx debugging (RECOMMENDED)" + depends on BCM43XX + default y + ---help--- + Broadcom 43xx debugging messages. + Say Y, because the driver is still very experimental and + this will help you get it running. + +config BCM43XX_DMA + bool +config BCM43XX_PIO + bool + +choice + prompt "BCM43xx data transfer mode" + depends on BCM43XX + default BCM43XX_DMA_AND_PIO + +config BCM43XX_DMA_AND_PIO_MODE + bool "DMA + PIO" + select BCM43XX_DMA + select BCM43XX_PIO + ---help--- + Include both, Direct Memory Access (DMA) and Programmed I/O (PIO) + data transfer modes. + The actually used mode is selectable through the module + parameter "pio". If the module parameter is pio=0, DMA is used. + Otherwise PIO is used. DMA is default. + + If unsure, choose this option. + +config BCM43XX_DMA_MODE + bool "DMA (Direct Memory Access) only" + select BCM43XX_DMA + ---help--- + Only include Direct Memory Access (DMA). + This reduces the size of the driver module, by omitting the PIO code. + +config BCM43XX_PIO_MODE + bool "PIO (Programmed I/O) only" + select BCM43XX_PIO + ---help--- + Only include Programmed I/O (PIO). + This reduces the size of the driver module, by omitting the DMA code. + Please note that PIO transfers are slow (compared to DMA). + Only use PIO, if DMA does not work for you. + +endchoice diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile index e025e9f052b..c87c1525b39 100644 --- a/drivers/net/wireless/bcm43xx/Makefile +++ b/drivers/net/wireless/bcm43xx/Makefile @@ -1,9 +1,11 @@ obj-$(CONFIG_BCM43XX) += bcm43xx.o bcm43xx-obj-$(CONFIG_BCM43XX_DEBUG) += bcm43xx_debugfs.o -bcm43xx-objs := bcm43xx_main.o bcm43xx_dma.o \ +bcm43xx-obj-$(CONFIG_BCM43XX_DMA) += bcm43xx_dma.o +bcm43xx-obj-$(CONFIG_BCM43XX_PIO) += bcm43xx_pio.o + +bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \ bcm43xx_radio.o bcm43xx_phy.o \ bcm43xx_power.o bcm43xx_wx.o \ - bcm43xx_pio.o bcm43xx_ilt.o \ bcm43xx_leds.o bcm43xx_ethtool.o \ $(bcm43xx-obj-y) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 981d563f573..3d8ac7e952c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -639,7 +639,7 @@ struct bcm43xx_private { u32 initialized:1, /* init_board() succeed */ was_initialized:1, /* for PCI suspend/resume. */ shutting_down:1, /* free_board() in progress */ - pio_mode:1, /* PIO (if true), or DMA (if false) used. */ + __using_pio:1, /* Internal, use bcm43xx_using_pio(). */ bad_frames_preempt:1, /* Use "Bad Frames Preemption" (default off) */ reg124_set_0x4:1, /* Some variable to keep track of IRQ stuff. */ powersaving:1, /* TRUE if we are in PowerSaving mode. FALSE otherwise. */ @@ -749,6 +749,33 @@ struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) return ieee80211softmac_priv(dev); } + +/* Helper function, which returns a boolean. + * TRUE, if PIO is used; FALSE, if DMA is used. + */ +#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO) +static inline +int bcm43xx_using_pio(struct bcm43xx_private *bcm) +{ + return bcm->__using_pio; +} +#elif defined(CONFIG_BCM43XX_DMA) +static inline +int bcm43xx_using_pio(struct bcm43xx_private *bcm) +{ + return 0; +} +#elif defined(CONFIG_BCM43XX_PIO) +static inline +int bcm43xx_using_pio(struct bcm43xx_private *bcm) +{ + return 1; +} +#else +# error "Using neither DMA nor PIO? Confused..." +#endif + + static inline int bcm43xx_num_80211_cores(struct bcm43xx_private *bcm) { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h index 93e99d61f2e..88ad34dff2f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -94,6 +94,10 @@ #define BCM43xx_TXRESUME_PERCENT 50 + +#ifdef CONFIG_BCM43XX_DMA + + struct sk_buff; struct bcm43xx_private; struct bcm43xx_xmitstatus; @@ -172,4 +176,46 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, struct ieee80211_txb *txb); void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring); + +#else /* CONFIG_BCM43XX_DMA */ + + +static inline +int bcm43xx_dma_init(struct bcm43xx_private *bcm) +{ + return 0; +} +static inline +void bcm43xx_dma_free(struct bcm43xx_private *bcm) +{ +} +static inline +int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, + u16 dmacontroller_mmio_base) +{ + return 0; +} +static inline +int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, + u16 dmacontroller_mmio_base) +{ + return 0; +} +static inline +int bcm43xx_dma_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + return 0; +} +static inline +void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ +} +static inline +void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) +{ +} + +#endif /* CONFIG_BCM43XX_DMA */ #endif /* BCM43xx_DMA_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 4c4a2d71ca0..4e49da99818 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -62,10 +62,15 @@ MODULE_LICENSE("GPL"); extern char *nvram_get(char *name); #endif -/* Module parameters */ +#if defined(CONFIG_BCM43XX_DMA) && defined(CONFIG_BCM43XX_PIO) static int modparam_pio; module_param_named(pio, modparam_pio, int, 0444); MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode"); +#elif defined(CONFIG_BCM43XX_DMA) +# define modparam_pio 0 +#elif defined(CONFIG_BCM43XX_PIO) +# define modparam_pio 1 +#endif static int modparam_bad_frames_preempt; module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444); @@ -1528,7 +1533,8 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) { u32 flags = 0x00040000; - if ((bcm43xx_core_enabled(bcm)) && (!bcm->pio_mode)) { + if ((bcm43xx_core_enabled(bcm)) && + !bcm43xx_using_pio(bcm)) { //FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here? #ifndef CONFIG_BCM947XX /* reset all used DMA controllers. */ @@ -1635,7 +1641,7 @@ static inline void handle_irq_transmit_status(struct bcm43xx_private *bcm) } //TODO: There are more (unknown) flags to test. see bcm43xx_main.h - if (bcm->pio_mode) + if (bcm43xx_using_pio(bcm)) bcm43xx_pio_handle_xmitstatus(bcm, &stat); else bcm43xx_dma_handle_xmitstatus(bcm, &stat); @@ -1933,7 +1939,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE)); assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE)); if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) { - if (bcm->pio_mode) + if (bcm43xx_using_pio(bcm)) bcm43xx_pio_rx(bcm->current_core->pio->queue0); else bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0); @@ -1941,7 +1947,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) } if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { if (likely(bcm->current_core->rev < 5)) { - if (bcm->pio_mode) + if (bcm43xx_using_pio(bcm)) bcm43xx_pio_rx(bcm->current_core->pio->queue3); else bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1); @@ -1999,7 +2005,7 @@ void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) & 0x0001dc00; - if ((bcm->pio_mode) && + if (bcm43xx_using_pio(bcm) && (bcm->current_core->rev < 3) && (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) { /* Apply a PIO specific workaround to the dma_reasons */ @@ -2624,7 +2630,7 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) value32 |= 0x100000; //FIXME: What's this? Is this correct? bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); - if (bcm->pio_mode) { + if (bcm43xx_using_pio(bcm)) { bcm43xx_write32(bcm, 0x0210, 0x00000100); bcm43xx_write32(bcm, 0x0230, 0x00000100); bcm43xx_write32(bcm, 0x0250, 0x00000100); @@ -3123,15 +3129,12 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) if (bcm->current_core->rev >= 5) bcm43xx_write16(bcm, 0x043C, 0x000C); - if (!bcm->pio_mode) { - err = bcm43xx_dma_init(bcm); - if (err) - goto err_chip_cleanup; - } else { + if (bcm43xx_using_pio(bcm)) err = bcm43xx_pio_init(bcm); - if (err) - goto err_chip_cleanup; - } + else + err = bcm43xx_dma_init(bcm); + if (err) + goto err_chip_cleanup; bcm43xx_write16(bcm, 0x0612, 0x0050); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0416, 0x0050); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0414, 0x01F4); @@ -4001,8 +4004,8 @@ static inline int bcm43xx_tx(struct bcm43xx_private *bcm, { int err = -ENODEV; - if (bcm->pio_mode) - err = bcm43xx_pio_transfer_txb(bcm, txb); + if (bcm43xx_using_pio(bcm)) + err = bcm43xx_pio_tx(bcm, txb); else err = bcm43xx_dma_tx(bcm, txb); @@ -4158,10 +4161,10 @@ static int bcm43xx_net_stop(struct net_device *net_dev) return 0; } -static void bcm43xx_init_private(struct bcm43xx_private *bcm, - struct net_device *net_dev, - struct pci_dev *pci_dev, - struct workqueue_struct *wq) +static int bcm43xx_init_private(struct bcm43xx_private *bcm, + struct net_device *net_dev, + struct pci_dev *pci_dev, + struct workqueue_struct *wq) { bcm->ieee = netdev_priv(net_dev); bcm->softmac = ieee80211_priv(net_dev); @@ -4190,13 +4193,17 @@ static void bcm43xx_init_private(struct bcm43xx_private *bcm, (unsigned long)bcm); tasklet_disable_nosync(&bcm->isr_tasklet); if (modparam_pio) { - bcm->pio_mode = 1; + bcm->__using_pio = 1; } else { - if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK) == 0) { - bcm->pio_mode = 0; - } else { + if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK)) { +#ifdef CONFIG_BCM43XX_PIO printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n"); - bcm->pio_mode = 1; + bcm->__using_pio = 1; +#else + printk(KERN_ERR PFX "FATAL: DMA not supported and PIO not configured. " + "Recompile the driver with PIO support, please.\n"); + return -ENODEV; +#endif /* CONFIG_BCM43XX_PIO */ } } bcm->rts_threshold = BCM43xx_DEFAULT_RTS_THRESHOLD; @@ -4210,6 +4217,8 @@ static void bcm43xx_init_private(struct bcm43xx_private *bcm, bcm->ieee->tx_headroom = sizeof(struct bcm43xx_txhdr); bcm->ieee->set_security = bcm43xx_ieee80211_set_security; bcm->ieee->hard_start_xmit = bcm43xx_ieee80211_hard_start_xmit; + + return 0; } static int __devinit bcm43xx_init_one(struct pci_dev *pdev, @@ -4261,7 +4270,9 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, err = -ENOMEM; goto err_free_netdev; } - bcm43xx_init_private(bcm, net_dev, pdev, wq); + err = bcm43xx_init_private(bcm, net_dev, pdev, wq); + if (err) + goto err_destroy_wq; pci_set_drvdata(pdev, net_dev); @@ -4325,7 +4336,9 @@ static void bcm43xx_chip_reset(void *_bcm) bcm43xx_free_board(bcm); bcm->firmware_norelease = 0; bcm43xx_detach_board(bcm); - bcm43xx_init_private(bcm, net_dev, pci_dev, wq); + err = bcm43xx_init_private(bcm, net_dev, pci_dev, wq); + if (err) + goto failure; err = bcm43xx_attach_board(bcm); if (err) goto failure; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 9a55e9d0052..0bf4b3e26f9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -30,81 +30,88 @@ #include -static inline -u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue, - u16 offset) +static void tx_start(struct bcm43xx_pioqueue *queue) { - return bcm43xx_read16(queue->bcm, queue->mmio_base + offset); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_INIT); } -static inline -void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue, - u16 offset, u16 value) +static void tx_octet(struct bcm43xx_pioqueue *queue, + u8 octet) { - bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value); + if (queue->need_workarounds) { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, + octet); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_WRITEHI); + } else { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_WRITEHI); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, + octet); + } } -static inline -void tx_start(struct bcm43xx_pioqueue *queue) +static u16 tx_get_next_word(struct bcm43xx_txhdr *txhdr, + const u8 *packet, + unsigned int *pos) { - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_INIT); -} + const u8 *source; + unsigned int i = *pos; + u16 ret; -static inline -void tx_octet(struct bcm43xx_pioqueue *queue, - u8 octet) -{ - if (queue->bcm->current_core->rev < 3) { - bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet); - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI); + if (i < sizeof(*txhdr)) { + source = (const u8 *)txhdr; } else { - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_WRITEHI); - bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, octet); + source = packet; + i -= sizeof(*txhdr); } + ret = le16_to_cpu( *((u16 *)(source + i)) ); + *pos += 2; + + return ret; } -static inline -void tx_data(struct bcm43xx_pioqueue *queue, - u8 *packet, - unsigned int octets) +static void tx_data(struct bcm43xx_pioqueue *queue, + struct bcm43xx_txhdr *txhdr, + const u8 *packet, + unsigned int octets) { u16 data; unsigned int i = 0; - if (queue->bcm->current_core->rev < 3) { - data = be16_to_cpu( *((u16 *)packet) ); + if (queue->need_workarounds) { + data = tx_get_next_word(txhdr, packet, &i); bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); - i += 2; } bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, - BCM43xx_PIO_TXCTL_WRITELO | BCM43xx_PIO_TXCTL_WRITEHI); - for ( ; i < octets - 1; i += 2) { - data = be16_to_cpu( *((u16 *)(packet + i)) ); + BCM43xx_PIO_TXCTL_WRITELO | + BCM43xx_PIO_TXCTL_WRITEHI); + while (i < octets - 1) { + data = tx_get_next_word(txhdr, packet, &i); bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); } if (octets % 2) - tx_octet(queue, packet[octets - 1]); + tx_octet(queue, packet[octets - sizeof(*txhdr) - 1]); } -static inline -void tx_complete(struct bcm43xx_pioqueue *queue, - struct sk_buff *skb) +static void tx_complete(struct bcm43xx_pioqueue *queue, + struct sk_buff *skb) { - u16 data; - - if (queue->bcm->current_core->rev < 3) { - data = be16_to_cpu( *((u16 *)(skb->data + skb->len - 2)) ); - bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, data); + if (queue->need_workarounds) { + bcm43xx_pio_write(queue, BCM43xx_PIO_TXDATA, + skb->data[skb->len - 1]); bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, - BCM43xx_PIO_TXCTL_WRITEHI | BCM43xx_PIO_TXCTL_COMPLETE); + BCM43xx_PIO_TXCTL_WRITEHI | + BCM43xx_PIO_TXCTL_COMPLETE); } else { - bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, BCM43xx_PIO_TXCTL_COMPLETE); + bcm43xx_pio_write(queue, BCM43xx_PIO_TXCTL, + BCM43xx_PIO_TXCTL_COMPLETE); } } -static inline -u16 generate_cookie(struct bcm43xx_pioqueue *queue, - int packetindex) +static u16 generate_cookie(struct bcm43xx_pioqueue *queue, + int packetindex) { u16 cookie = 0x0000; @@ -113,8 +120,6 @@ u16 generate_cookie(struct bcm43xx_pioqueue *queue, * for the packet index (in the cache). */ switch (queue->mmio_base) { - default: - assert(0); case BCM43xx_MMIO_PIO1_BASE: break; case BCM43xx_MMIO_PIO2_BASE: @@ -126,6 +131,8 @@ u16 generate_cookie(struct bcm43xx_pioqueue *queue, case BCM43xx_MMIO_PIO4_BASE: cookie = 0x3000; break; + default: + assert(0); } assert(((u16)packetindex & 0xF000) == 0x0000); cookie |= (u16)packetindex; @@ -133,66 +140,75 @@ u16 generate_cookie(struct bcm43xx_pioqueue *queue, return cookie; } -static inline +static struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm, u16 cookie, struct bcm43xx_pio_txpacket **packet) { + struct bcm43xx_pio *pio = bcm->current_core->pio; struct bcm43xx_pioqueue *queue = NULL; int packetindex; switch (cookie & 0xF000) { case 0x0000: - queue = bcm->current_core->pio->queue0; + queue = pio->queue0; break; case 0x1000: - queue = bcm->current_core->pio->queue1; + queue = pio->queue1; break; case 0x2000: - queue = bcm->current_core->pio->queue2; + queue = pio->queue2; break; case 0x3000: - queue = bcm->current_core->pio->queue3; + queue = pio->queue3; break; default: assert(0); } - packetindex = (cookie & 0x0FFF); assert(packetindex >= 0 && packetindex < BCM43xx_PIO_MAXTXPACKETS); - *packet = queue->__tx_packets_cache + packetindex; + *packet = &(queue->tx_packets_cache[packetindex]); return queue; } -static inline -void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue, - struct sk_buff *skb, - struct bcm43xx_pio_txpacket *packet) +static void pio_tx_write_fragment(struct bcm43xx_pioqueue *queue, + struct sk_buff *skb, + struct bcm43xx_pio_txpacket *packet) { + struct bcm43xx_txhdr txhdr; unsigned int octets; assert(skb_shinfo(skb)->nr_frags == 0); - assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); - - __skb_push(skb, sizeof(struct bcm43xx_txhdr)); bcm43xx_generate_txhdr(queue->bcm, - (struct bcm43xx_txhdr *)skb->data, - skb->data + sizeof(struct bcm43xx_txhdr), - skb->len - sizeof(struct bcm43xx_txhdr), + &txhdr, skb->data, skb->len, (packet->xmitted_frags == 0), generate_cookie(queue, pio_txpacket_getindex(packet))); tx_start(queue); - octets = skb->len; - if (queue->bcm->current_core->rev < 3) //FIXME: && this is the last packet in the queue. - octets -= 2; - tx_data(queue, (u8 *)skb->data, octets); + octets = skb->len + sizeof(txhdr); + if (queue->need_workarounds) + octets--; + tx_data(queue, &txhdr, (u8 *)skb->data, octets); tx_complete(queue, skb); } -static inline -int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) +static void free_txpacket(struct bcm43xx_pio_txpacket *packet, + int irq_context) +{ + struct bcm43xx_pioqueue *queue = packet->queue; + + ieee80211_txb_free(packet->txb); + list_move(&packet->list, &queue->txfree); + queue->nr_txfree++; + + assert(queue->tx_devq_used >= packet->xmitted_octets); + assert(queue->tx_devq_packets >= packet->xmitted_frags); + queue->tx_devq_used -= packet->xmitted_octets; + queue->tx_devq_packets -= packet->xmitted_frags; +} + +static int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) { struct bcm43xx_pioqueue *queue = packet->queue; struct ieee80211_txb *txb = packet->txb; @@ -204,12 +220,11 @@ int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) skb = txb->fragments[i]; octets = (u16)skb->len + sizeof(struct bcm43xx_txhdr); - assert(queue->tx_devq_size >= octets); assert(queue->tx_devq_packets <= BCM43xx_PIO_MAXTXDEVQPACKETS); assert(queue->tx_devq_used <= queue->tx_devq_size); /* Check if there is sufficient free space on the device - * TX queue. If not, return and let the TX-work-handler + * TX queue. If not, return and let the TX tasklet * retry later. */ if (queue->tx_devq_packets == BCM43xx_PIO_MAXTXDEVQPACKETS) @@ -234,28 +249,15 @@ int pio_tx_packet(struct bcm43xx_pio_txpacket *packet) return 0; } -static void free_txpacket(struct bcm43xx_pio_txpacket *packet) +static void tx_tasklet(unsigned long d) { - struct bcm43xx_pioqueue *queue = packet->queue; - - ieee80211_txb_free(packet->txb); - - list_move(&packet->list, &packet->queue->txfree); - - assert(queue->tx_devq_used >= packet->xmitted_octets); - queue->tx_devq_used -= packet->xmitted_octets; - assert(queue->tx_devq_packets >= packet->xmitted_frags); - queue->tx_devq_packets -= packet->xmitted_frags; -} - -static void txwork_handler(void *d) -{ - struct bcm43xx_pioqueue *queue = d; + struct bcm43xx_pioqueue *queue = (struct bcm43xx_pioqueue *)d; + struct bcm43xx_private *bcm = queue->bcm; unsigned long flags; struct bcm43xx_pio_txpacket *packet, *tmp_packet; int err; - spin_lock_irqsave(&queue->txlock, flags); + spin_lock_irqsave(&bcm->lock, flags); list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { assert(packet->xmitted_frags < packet->txb->nr_frags); if (packet->xmitted_frags == 0) { @@ -270,22 +272,22 @@ static void txwork_handler(void *d) skb = packet->txb->fragments[i]; if (unlikely(skb->len > queue->tx_devq_size)) { dprintkl(KERN_ERR PFX "PIO TX device queue too small. " - "Dropping packet...\n"); - free_txpacket(packet); + "Dropping packet.\n"); + free_txpacket(packet, 1); goto next_packet; } } } - /* Now try to transmit the packet. + /* Try to transmit the packet. * This may not completely succeed. */ err = pio_tx_packet(packet); if (err) break; -next_packet: + next_packet: continue; } - spin_unlock_irqrestore(&queue->txlock, flags); + spin_unlock_irqrestore(&bcm->lock, flags); } static void setup_txqueues(struct bcm43xx_pioqueue *queue) @@ -293,8 +295,9 @@ static void setup_txqueues(struct bcm43xx_pioqueue *queue) struct bcm43xx_pio_txpacket *packet; int i; + queue->nr_txfree = BCM43xx_PIO_MAXTXPACKETS; for (i = 0; i < BCM43xx_PIO_MAXTXPACKETS; i++) { - packet = queue->__tx_packets_cache + i; + packet = &(queue->tx_packets_cache[i]); packet->queue = queue; INIT_LIST_HEAD(&packet->list); @@ -311,19 +314,19 @@ struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm, u32 value; u16 qsize; - queue = kmalloc(sizeof(*queue), GFP_KERNEL); + queue = kzalloc(sizeof(*queue), GFP_KERNEL); if (!queue) goto out; - memset(queue, 0, sizeof(*queue)); queue->bcm = bcm; queue->mmio_base = pio_mmio_base; + queue->need_workarounds = (bcm->current_core->rev < 3); INIT_LIST_HEAD(&queue->txfree); INIT_LIST_HEAD(&queue->txqueue); INIT_LIST_HEAD(&queue->txrunning); - spin_lock_init(&queue->txlock); - INIT_WORK(&queue->txwork, txwork_handler, queue); + tasklet_init(&queue->txtask, tx_tasklet, + (unsigned long)queue); value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); value |= BCM43xx_SBF_XFER_REG_BYTESWAP; @@ -331,7 +334,7 @@ struct bcm43xx_pioqueue * bcm43xx_setup_pioqueue(struct bcm43xx_private *bcm, qsize = bcm43xx_read16(bcm, queue->mmio_base + BCM43xx_PIO_TXQBUFSIZE); if (qsize <= BCM43xx_PIO_TXQADJUST) { - printk(KERN_ERR PFX "PIO tx queue too small (%u)\n", qsize); + printk(KERN_ERR PFX "PIO tx device-queue too small (%u)\n", qsize); goto err_freequeue; } qsize -= BCM43xx_PIO_TXQADJUST; @@ -354,13 +357,12 @@ static void cancel_transfers(struct bcm43xx_pioqueue *queue) netif_tx_disable(queue->bcm->net_dev); assert(queue->bcm->shutting_down); - cancel_delayed_work(&queue->txwork); - flush_workqueue(queue->bcm->workqueue); + tasklet_disable(&queue->txtask); list_for_each_entry_safe(packet, tmp_packet, &queue->txrunning, list) - free_txpacket(packet); + free_txpacket(packet, 0); list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) - free_txpacket(packet); + free_txpacket(packet, 0); } static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) @@ -374,40 +376,43 @@ static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) void bcm43xx_pio_free(struct bcm43xx_private *bcm) { - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue3); - bcm->current_core->pio->queue3 = NULL; - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2); - bcm->current_core->pio->queue2 = NULL; - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1); - bcm->current_core->pio->queue1 = NULL; - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0); - bcm->current_core->pio->queue0 = NULL; + struct bcm43xx_pio *pio = bcm->current_core->pio; + + bcm43xx_destroy_pioqueue(pio->queue3); + pio->queue3 = NULL; + bcm43xx_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; + bcm43xx_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; + bcm43xx_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; } int bcm43xx_pio_init(struct bcm43xx_private *bcm) { + struct bcm43xx_pio *pio = bcm->current_core->pio; struct bcm43xx_pioqueue *queue; int err = -ENOMEM; queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO1_BASE); if (!queue) goto out; - bcm->current_core->pio->queue0 = queue; + pio->queue0 = queue; queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO2_BASE); if (!queue) goto err_destroy0; - bcm->current_core->pio->queue1 = queue; + pio->queue1 = queue; queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO3_BASE); if (!queue) goto err_destroy1; - bcm->current_core->pio->queue2 = queue; + pio->queue2 = queue; queue = bcm43xx_setup_pioqueue(bcm, BCM43xx_MMIO_PIO4_BASE); if (!queue) goto err_destroy2; - bcm->current_core->pio->queue3 = queue; + pio->queue3 = queue; if (bcm->current_core->rev < 3) bcm->irq_savedstate |= BCM43xx_IRQ_PIO_WORKAROUND; @@ -418,41 +423,38 @@ out: return err; err_destroy2: - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue2); - bcm->current_core->pio->queue2 = NULL; + bcm43xx_destroy_pioqueue(pio->queue2); + pio->queue2 = NULL; err_destroy1: - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue1); - bcm->current_core->pio->queue1 = NULL; + bcm43xx_destroy_pioqueue(pio->queue1); + pio->queue1 = NULL; err_destroy0: - bcm43xx_destroy_pioqueue(bcm->current_core->pio->queue0); - bcm->current_core->pio->queue0 = NULL; + bcm43xx_destroy_pioqueue(pio->queue0); + pio->queue0 = NULL; goto out; } -static inline -int pio_transfer_txb(struct bcm43xx_pioqueue *queue, - struct ieee80211_txb *txb) +int bcm43xx_pio_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) { + struct bcm43xx_pioqueue *queue = bcm->current_core->pio->queue1; struct bcm43xx_pio_txpacket *packet; - unsigned long flags; u16 tmp; - spin_lock_irqsave(&queue->txlock, flags); assert(!queue->tx_suspended); assert(!list_empty(&queue->txfree)); tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_TXCTL); - if (tmp & BCM43xx_PIO_TXCTL_SUSPEND) { - spin_unlock_irqrestore(&queue->txlock, flags); + if (tmp & BCM43xx_PIO_TXCTL_SUSPEND) return -EBUSY; - } packet = list_entry(queue->txfree.next, struct bcm43xx_pio_txpacket, list); - packet->txb = txb; - list_move_tail(&packet->list, &queue->txqueue); - packet->xmitted_octets = 0; packet->xmitted_frags = 0; + packet->xmitted_octets = 0; + list_move_tail(&packet->list, &queue->txqueue); + queue->nr_txfree--; + assert(queue->nr_txfree < BCM43xx_PIO_MAXTXPACKETS); /* Suspend TX, if we are out of packets in the "free" queue. */ if (unlikely(list_empty(&queue->txfree))) { @@ -460,69 +462,66 @@ int pio_transfer_txb(struct bcm43xx_pioqueue *queue, queue->tx_suspended = 1; } - spin_unlock_irqrestore(&queue->txlock, flags); - queue_work(queue->bcm->workqueue, &queue->txwork); + tasklet_schedule(&queue->txtask); return 0; } -int fastcall bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb) -{ - return pio_transfer_txb(bcm->current_core->pio->queue1, txb); -} - -void fastcall -bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status) +void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) { struct bcm43xx_pioqueue *queue; struct bcm43xx_pio_txpacket *packet; - unsigned long flags; queue = parse_cookie(bcm, status->cookie, &packet); assert(queue); - spin_lock_irqsave(&queue->txlock, flags); - free_txpacket(packet); +//TODO +if (!queue) +return; + free_txpacket(packet, 1); if (unlikely(queue->tx_suspended)) { queue->tx_suspended = 0; netif_wake_queue(queue->bcm->net_dev); } - - /* If there are packets on the txqueue, - * start the work handler again. - */ - if (!list_empty(&queue->txqueue)) { - queue_work(queue->bcm->workqueue, - &queue->txwork); - } - spin_unlock_irqrestore(&queue->txlock, flags); + /* If there are packets on the txqueue, poke the tasklet. */ + if (!list_empty(&queue->txqueue)) + tasklet_schedule(&queue->txtask); } static void pio_rx_error(struct bcm43xx_pioqueue *queue, + int clear_buffers, const char *error) { - printk("PIO RX error: %s\n", error); - bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_READY); + int i; + + printkl("PIO RX error: %s\n", error); + bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, + BCM43xx_PIO_RXCTL_READY); + if (clear_buffers) { + assert(queue->mmio_base == BCM43xx_MMIO_PIO1_BASE); + for (i = 0; i < 15; i++) { + /* Dummy read. */ + bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); + } + } } -void fastcall -bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) +void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) { u16 preamble[21] = { 0 }; struct bcm43xx_rxhdr *rxhdr; - u16 tmp; - u16 len; - int i, err; - int preamble_readwords; + u16 tmp, len, rxflags2; + int i, preamble_readwords; struct sk_buff *skb; +return; tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); if (!(tmp & BCM43xx_PIO_RXCTL_DATAAVAILABLE)) { - dprintkl(KERN_ERR PFX "PIO RX: No data available\n"); + dprintkl(KERN_ERR PFX "PIO RX: No data available\n");//TODO: remove this printk. return; } - bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, BCM43xx_PIO_RXCTL_DATAAVAILABLE); + bcm43xx_pio_write(queue, BCM43xx_PIO_RXCTL, + BCM43xx_PIO_RXCTL_DATAAVAILABLE); for (i = 0; i < 10; i++) { tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXCTL); @@ -534,13 +533,14 @@ bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) return; data_ready: +//FIXME: endianess in this function. len = le16_to_cpu(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); if (unlikely(len > 0x700)) { - pio_rx_error(queue, "len > 0x700"); + pio_rx_error(queue, 0, "len > 0x700"); return; } if (unlikely(len == 0 && queue->mmio_base != BCM43xx_MMIO_PIO4_BASE)) { - pio_rx_error(queue, "len == 0"); + pio_rx_error(queue, 0, "len == 0"); return; } preamble[0] = cpu_to_le16(len); @@ -550,28 +550,38 @@ data_ready: preamble_readwords = 18 / sizeof(u16); for (i = 0; i < preamble_readwords; i++) { tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); - preamble[i + 1] = cpu_to_be16(tmp); + preamble[i + 1] = cpu_to_be16(tmp);//FIXME? } rxhdr = (struct bcm43xx_rxhdr *)preamble; - if (unlikely(rxhdr->flags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) { - pio_rx_error(queue, "invalid frame"); - if (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE) { - for (i = 0; i < 15; i++) - bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); /* dummy read. */ - } + rxflags2 = le16_to_cpu(rxhdr->flags2); + if (unlikely(rxflags2 & BCM43xx_RXHDR_FLAGS2_INVALIDFRAME)) { + pio_rx_error(queue, + (queue->mmio_base == BCM43xx_MMIO_PIO1_BASE), + "invalid frame"); return; } -//FIXME -#if 0 if (queue->mmio_base == BCM43xx_MMIO_PIO4_BASE) { - bcm43xx_rx_transmitstatus(queue->bcm, - (const struct bcm43xx_hwxmitstatus *)(preamble + 1)); + /* We received an xmit status. */ + struct bcm43xx_hwxmitstatus *hw; + struct bcm43xx_xmitstatus stat; + + hw = (struct bcm43xx_hwxmitstatus *)(preamble + 1); + stat.cookie = le16_to_cpu(hw->cookie); + stat.flags = hw->flags; + stat.cnt1 = hw->cnt1; + stat.cnt2 = hw->cnt2; + stat.seq = le16_to_cpu(hw->seq); + stat.unknown = le16_to_cpu(hw->unknown); + + bcm43xx_debugfs_log_txstat(queue->bcm, &stat); + bcm43xx_pio_handle_xmitstatus(queue->bcm, &stat); + return; } -#endif + skb = dev_alloc_skb(len); if (unlikely(!skb)) { - pio_rx_error(queue, "out of memory"); + pio_rx_error(queue, 1, "OOM"); return; } skb_put(skb, len); @@ -580,13 +590,14 @@ data_ready: *((u16 *)(skb->data + i)) = tmp; } if (len % 2) { - tmp = cpu_to_be16(bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA)); + tmp = bcm43xx_pio_read(queue, BCM43xx_PIO_RXDATA); skb->data[len - 1] = (tmp & 0x00FF); - skb->data[0] = (tmp & 0xFF00) >> 8; + if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) + skb->data[0x20] = (tmp & 0xFF00) >> 8; + else + skb->data[0x1E] = (tmp & 0xFF00) >> 8; } - err = bcm43xx_rx(queue->bcm, skb, rxhdr); - if (unlikely(err)) - dev_kfree_skb_irq(skb); + bcm43xx_rx(queue->bcm, skb, rxhdr); } /* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h index 71b92ee3416..970627bc176 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.h @@ -3,9 +3,8 @@ #include "bcm43xx.h" +#include #include -#include -#include #include @@ -32,6 +31,10 @@ #define BCM43xx_PIO_MAXTXPACKETS 256 + +#ifdef CONFIG_BCM43XX_PIO + + struct bcm43xx_pioqueue; struct bcm43xx_xmitstatus; @@ -44,13 +47,14 @@ struct bcm43xx_pio_txpacket { u16 xmitted_octets; }; -#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->__tx_packets_cache)) +#define pio_txpacket_getindex(packet) ((int)((packet) - (packet)->queue->tx_packets_cache)) struct bcm43xx_pioqueue { struct bcm43xx_private *bcm; u16 mmio_base; - u8 tx_suspended:1; + u8 tx_suspended:1, + need_workarounds:1; /* Workarounds needed for core.rev < 3 */ /* Adjusted size of the device internal TX buffer. */ u16 tx_devq_size; @@ -62,6 +66,7 @@ struct bcm43xx_pioqueue { * be taken on incoming TX requests. */ struct list_head txfree; + unsigned int nr_txfree; /* Packets on the txqueue are queued, * but not completely written to the chip, yet. */ @@ -70,19 +75,64 @@ struct bcm43xx_pioqueue { * posted to the device. We are waiting for the txstatus. */ struct list_head txrunning; - /* Locking of the TX queues and the accounting. */ - spinlock_t txlock; - struct work_struct txwork; - struct bcm43xx_pio_txpacket __tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS]; + /* Total number or packets sent. + * (This counter can obviously wrap). + */ + unsigned int nr_tx_packets; + struct tasklet_struct txtask; + struct bcm43xx_pio_txpacket tx_packets_cache[BCM43xx_PIO_MAXTXPACKETS]; }; +static inline +u16 bcm43xx_pio_read(struct bcm43xx_pioqueue *queue, + u16 offset) +{ + return bcm43xx_read16(queue->bcm, queue->mmio_base + offset); +} + +static inline +void bcm43xx_pio_write(struct bcm43xx_pioqueue *queue, + u16 offset, u16 value) +{ + bcm43xx_write16(queue->bcm, queue->mmio_base + offset, value); +} + + int bcm43xx_pio_init(struct bcm43xx_private *bcm); void bcm43xx_pio_free(struct bcm43xx_private *bcm); -int FASTCALL(bcm43xx_pio_transfer_txb(struct bcm43xx_private *bcm, - struct ieee80211_txb *txb)); -void FASTCALL(bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, - struct bcm43xx_xmitstatus *status)); - -void FASTCALL(bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue)); +int bcm43xx_pio_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb); +void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status); +void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue); + +#else /* CONFIG_BCM43XX_PIO */ + +static inline +int bcm43xx_pio_init(struct bcm43xx_private *bcm) +{ + return 0; +} +static inline +void bcm43xx_pio_free(struct bcm43xx_private *bcm) +{ +} +static inline +int bcm43xx_pio_tx(struct bcm43xx_private *bcm, + struct ieee80211_txb *txb) +{ + return 0; +} +static inline +void bcm43xx_pio_handle_xmitstatus(struct bcm43xx_private *bcm, + struct bcm43xx_xmitstatus *status) +{ +} +static inline +void bcm43xx_pio_rx(struct bcm43xx_pioqueue *queue) +{ +} + +#endif /* CONFIG_BCM43XX_PIO */ #endif /* BCM43xx_PIO_H_ */ -- cgit v1.2.3 From 8bcab3f55982cf28310f2303bef741424ad0f563 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 12 Feb 2006 16:52:10 +0100 Subject: [PATCH] bcm43xx: add a note that not all devices support PIO. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/Kconfig | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig index d8d23155ee3..1d677c15b21 100644 --- a/drivers/net/wireless/bcm43xx/Kconfig +++ b/drivers/net/wireless/bcm43xx/Kconfig @@ -52,6 +52,11 @@ config BCM43XX_PIO_MODE Only include Programmed I/O (PIO). This reduces the size of the driver module, by omitting the DMA code. Please note that PIO transfers are slow (compared to DMA). + + Also note that not all devices of the 43xx series support PIO. + The 4306 (Apple Airport Extreme and others) supports PIO, while + the 4318 is known to _not_ support PIO. + Only use PIO, if DMA does not work for you. endchoice -- cgit v1.2.3 From f1f566236dcc4cb57cfae89b539e19c1290e7f34 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 12 Feb 2006 16:55:06 +0100 Subject: [PATCH] Apple Airport: Add Kconfig note that the bcm43xx driver has to be used for Airport Extreme cards. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 5c4d7b4ece5..9c01fb26c8f 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -309,7 +309,10 @@ config APPLE_AIRPORT Say Y here to support the Airport 802.11b wireless Ethernet hardware built into the Macintosh iBook and other recent PowerPC-based Macintosh machines. This is essentially a Lucent Orinoco card with - a non-standard interface + a non-standard interface. + + This driver does not support the Airport Extreme (802.11b/g). Use + the BCM43xx driver for Airport Extreme cards. config PLX_HERMES tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)" -- cgit v1.2.3 From dcfd720bd733544606b053e8e68b7419211ace72 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 12 Feb 2006 20:25:55 +0100 Subject: [PATCH] bcm43xx: fix LED code. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 88 +++++++++++++++++++---------- drivers/net/wireless/bcm43xx/bcm43xx_leds.h | 11 +++- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 2 +- 3 files changed, 68 insertions(+), 33 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index 455a0c743f7..8f550c1a92e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -35,12 +35,13 @@ static void bcm43xx_led_changestate(struct bcm43xx_led *led) { struct bcm43xx_private *bcm = led->bcm; const int index = bcm43xx_led_index(led); + const u16 mask = (1 << index); u16 ledctl; assert(index >= 0 && index < BCM43xx_NR_LEDS); assert(led->blink_interval); ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); - __change_bit(index, (unsigned long *)(&ledctl)); + ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask); bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); } @@ -61,6 +62,8 @@ static void bcm43xx_led_blink(unsigned long d) static void bcm43xx_led_blink_start(struct bcm43xx_led *led, unsigned long interval) { + if (led->blink_interval) + return; led->blink_interval = interval; bcm43xx_led_changestate(led); led->blink_timer.expires = jiffies + interval; @@ -91,6 +94,39 @@ static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync) bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); } +static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm, + struct bcm43xx_led *led, + int led_index) +{ + /* This function is called, if the behaviour (and activelow) + * information for a LED is missing in the SPROM. + * We hardcode the behaviour values for various devices here. + * Note that the BCM43xx_LED_TEST_XXX behaviour values can + * be used to figure out which led is mapped to which index. + */ + + switch (led_index) { + case 0: + led->behaviour = BCM43xx_LED_ACTIVITY; + if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ) + led->behaviour = BCM43xx_LED_RADIO_ALL; + break; + case 1: + led->behaviour = BCM43xx_LED_RADIO_B; + if (bcm->board_vendor == PCI_VENDOR_ID_ASUSTEK) + led->behaviour = BCM43xx_LED_ASSOC; + break; + case 2: + led->behaviour = BCM43xx_LED_RADIO_A; + break; + case 3: + led->behaviour = BCM43xx_LED_OFF; + break; + default: + assert(0); + } +} + int bcm43xx_leds_init(struct bcm43xx_private *bcm) { struct bcm43xx_led *led; @@ -105,31 +141,12 @@ int bcm43xx_leds_init(struct bcm43xx_private *bcm) for (i = 0; i < BCM43xx_NR_LEDS; i++) { led = &(bcm->leds[i]); led->bcm = bcm; - init_timer(&led->blink_timer); - led->blink_timer.data = (unsigned long)led; - led->blink_timer.function = bcm43xx_led_blink; + setup_timer(&led->blink_timer, + bcm43xx_led_blink, + (unsigned long)led); if (sprom[i] == 0xFF) { - /* SPROM information not set. */ - switch (i) { - case 0: - if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ) - led->behaviour = BCM43xx_LED_RADIO_ALL; - else - led->behaviour = BCM43xx_LED_ACTIVITY; - break; - case 1: - led->behaviour = BCM43xx_LED_RADIO_B; - break; - case 2: - led->behaviour = BCM43xx_LED_RADIO_A; - break; - case 3: - led->behaviour = BCM43xx_LED_OFF; - break; - default: - assert(0); - } + bcm43xx_led_init_hardcoded(bcm, led, i); } else { led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR; led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW); @@ -157,19 +174,19 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) struct bcm43xx_radioinfo *radio = bcm->current_core->radio; struct bcm43xx_phyinfo *phy = bcm->current_core->phy; const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES; - int i, turn_on = 0; + int i, turn_on; unsigned long interval = 0; u16 ledctl; ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); for (i = 0; i < BCM43xx_NR_LEDS; i++) { led = &(bcm->leds[i]); - if (led->behaviour == BCM43xx_LED_INACTIVE) - continue; + turn_on = 0; switch (led->behaviour) { + case BCM43xx_LED_INACTIVE: + continue; case BCM43xx_LED_OFF: - turn_on = 0; break; case BCM43xx_LED_ON: turn_on = 1; @@ -189,7 +206,6 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) phy->type == BCM43xx_PHYTYPE_G)); break; case BCM43xx_LED_MODE_BG: - turn_on = 0; if (phy->type == BCM43xx_PHYTYPE_G && 1/*FIXME: using G rates.*/) turn_on = 1; @@ -222,12 +238,22 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) continue; case BCM43xx_LED_WEIRD: //TODO - turn_on = 0; break; case BCM43xx_LED_ASSOC: - if (1/*TODO: associated*/) + if (bcm->softmac->associated) turn_on = 1; break; +#ifdef CONFIG_BCM43XX_DEBUG + case BCM43xx_LED_TEST_BLINKSLOW: + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW); + continue; + case BCM43xx_LED_TEST_BLINKMEDIUM: + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM); + continue; + case BCM43xx_LED_TEST_BLINKFAST: + bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST); + continue; +#endif /* CONFIG_BCM43XX_DEBUG */ default: assert(0); }; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h index 489a2b1e906..6f18e2f95db 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h @@ -16,7 +16,7 @@ struct bcm43xx_led { #define bcm43xx_led_index(led) ((int)((led) - (led)->bcm->leds)) /* Delay between state changes when blinking in jiffies */ -#define BCM43xx_LEDBLINK_SLOW (HZ / 2) +#define BCM43xx_LEDBLINK_SLOW (HZ / 1) #define BCM43xx_LEDBLINK_MEDIUM (HZ / 4) #define BCM43xx_LEDBLINK_FAST (HZ / 8) @@ -37,6 +37,15 @@ enum { /* LED behaviour values */ BCM43xx_LED_WEIRD,//FIXME BCM43xx_LED_ASSOC, BCM43xx_LED_INACTIVE, + + /* Behaviour values for testing. + * With these values it is easier to figure out + * the real behaviour of leds, in case the SPROM + * is missing information. + */ + BCM43xx_LED_TEST_BLINKSLOW, + BCM43xx_LED_TEST_BLINKMEDIUM, + BCM43xx_LED_TEST_BLINKFAST, }; int bcm43xx_leds_init(struct bcm43xx_private *bcm); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 4e49da99818..fbf931d4a13 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1943,7 +1943,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) bcm43xx_pio_rx(bcm->current_core->pio->queue0); else bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0); - activity = 1; + /* We intentionally don't set "activity" to 1, here. */ } if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { if (likely(bcm->current_core->rev < 5)) { -- cgit v1.2.3 From ab4977f881fc23cb02ef6f20d1e8ebbdcfef75ad Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 12 Feb 2006 22:40:39 +0100 Subject: [PATCH] bcm43xx: rewrite and simplify the periodic task handling. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 13 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 194 ++++++++++------------------ 2 files changed, 73 insertions(+), 134 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 3d8ac7e952c..99b2e72281e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -418,7 +418,6 @@ enum { struct net_device; struct pci_dev; -struct workqueue_struct; struct bcm43xx_dmaring; struct bcm43xx_pioqueue; @@ -706,18 +705,10 @@ struct bcm43xx_private { /* Interrupt Service Routine tasklet (bottom-half) */ struct tasklet_struct isr_tasklet; - /* Custom driver work queue. */ - struct workqueue_struct *workqueue; /* Periodic tasks */ - struct work_struct periodic_work0; -#define BCM43xx_PERIODIC_0_DELAY (HZ * 15) - struct work_struct periodic_work1; -#define BCM43xx_PERIODIC_1_DELAY ((HZ * 60) + HZ / 2) - struct work_struct periodic_work2; -#define BCM43xx_PERIODIC_2_DELAY ((HZ * 120) + HZ) - struct work_struct periodic_work3; -#define BCM43xx_PERIODIC_3_DELAY ((HZ * 30) + HZ / 5) + struct timer_list periodic_tasks; + unsigned int periodic_state; struct work_struct restart_work; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index fbf931d4a13..18152b0b2dd 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2939,7 +2939,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) core->phy->minlowsigpos[1] = 0; spin_lock_init(&core->phy->lock); core->radio = &bcm->radio[i]; - core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; + core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; core->radio->channel = 0xFF; core->radio->initial_channel = 0xFF; core->radio->lofcal = 0xFFFF; @@ -3261,144 +3261,104 @@ static void bcm43xx_softmac_init(struct bcm43xx_private *bcm) ieee80211softmac_start(bcm->net_dev); } -static void bcm43xx_periodic_work0_handler(void *d) +static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) { - struct bcm43xx_private *bcm = d; - unsigned long flags; - //TODO: unsigned int aci_average; - - spin_lock_irqsave(&bcm->lock, flags); + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { - //FIXME: aci_average = bcm43xx_update_aci_average(bcm); - if (bcm->current_core->radio->aci_enable && bcm->current_core->radio->aci_wlan_automatic) { - bcm43xx_mac_suspend(bcm); - if (!bcm->current_core->radio->aci_enable && - 1 /*FIXME: We are not scanning? */) { - /*FIXME: First add bcm43xx_update_aci_average() before - * uncommenting this: */ - //if (bcm43xx_radio_aci_scan) - // bcm43xx_radio_set_interference_mitigation(bcm, - // BCM43xx_RADIO_INTERFMODE_MANUALWLAN); - } else if (1/*FIXME*/) { - //if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) - // bcm43xx_radio_set_interference_mitigation(bcm, - // BCM43xx_RADIO_INTERFMODE_MANUALWLAN); - } - bcm43xx_mac_enable(bcm); - } else if (bcm->current_core->radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN) { - if (bcm->current_core->phy->rev == 1) { - //FIXME: implement rev1 workaround - } - } - } - bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning? - //TODO for APHY (temperature?) + if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2) + return; - if (likely(!bcm->shutting_down)) { - queue_delayed_work(bcm->workqueue, &bcm->periodic_work0, - BCM43xx_PERIODIC_0_DELAY); - } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_mac_suspend(bcm); + bcm43xx_phy_lo_g_measure(bcm); + bcm43xx_mac_enable(bcm); } -static void bcm43xx_periodic_work1_handler(void *d) +static void bcm43xx_periodic_every60sec(struct bcm43xx_private *bcm) { - struct bcm43xx_private *bcm = d; - unsigned long flags; - - spin_lock_irqsave(&bcm->lock, flags); - bcm43xx_phy_lo_mark_all_unused(bcm); if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { bcm43xx_mac_suspend(bcm); bcm43xx_calc_nrssi_slope(bcm); bcm43xx_mac_enable(bcm); } - - if (likely(!bcm->shutting_down)) { - queue_delayed_work(bcm->workqueue, &bcm->periodic_work1, - BCM43xx_PERIODIC_1_DELAY); - } - spin_unlock_irqrestore(&bcm->lock, flags); } -static void bcm43xx_periodic_work2_handler(void *d) +static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm) { - struct bcm43xx_private *bcm = d; - unsigned long flags; - - spin_lock_irqsave(&bcm->lock, flags); - - assert(bcm->current_core->phy->type == BCM43xx_PHYTYPE_G); - assert(bcm->current_core->phy->rev >= 2); + /* Update device statistics. */ + bcm43xx_calculate_link_quality(bcm); +} - bcm43xx_mac_suspend(bcm); - bcm43xx_phy_lo_g_measure(bcm); - bcm43xx_mac_enable(bcm); +static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - if (likely(!bcm->shutting_down)) { - queue_delayed_work(bcm->workqueue, &bcm->periodic_work2, - BCM43xx_PERIODIC_2_DELAY); + if (phy->type == BCM43xx_PHYTYPE_G) { + //TODO: update_aci_moving_average + if (radio->aci_enable && radio->aci_wlan_automatic) { + bcm43xx_mac_suspend(bcm); + if (!radio->aci_enable && 1 /*TODO: not scanning? */) { + if (0 /*TODO: bunch of conditions*/) { + bcm43xx_radio_set_interference_mitigation(bcm, + BCM43xx_RADIO_INTERFMODE_MANUALWLAN); + } + } else if (1/*TODO*/) { + /* + if ((aci_average > 1000) && !(bcm43xx_radio_aci_scan(bcm))) { + bcm43xx_radio_set_interference_mitigation(bcm, + BCM43xx_RADIO_INTERFMODE_NONE); + } + */ + } + bcm43xx_mac_enable(bcm); + } else if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN && + phy->rev == 1) { + //TODO: implement rev1 workaround + } } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning? + //TODO for APHY (temperature?) } -static void bcm43xx_periodic_work3_handler(void *d) +static void bcm43xx_periodic_task_handler(unsigned long d) { - struct bcm43xx_private *bcm = d; + struct bcm43xx_private *bcm = (struct bcm43xx_private *)d; unsigned long flags; + unsigned int state; spin_lock_irqsave(&bcm->lock, flags); - /* Update device statistics. */ - bcm43xx_calculate_link_quality(bcm); + assert(bcm->initialized); + state = bcm->periodic_state; + if (state % 8 == 0) + bcm43xx_periodic_every120sec(bcm); + if (state % 4 == 0) + bcm43xx_periodic_every60sec(bcm); + if (state % 2 == 0) + bcm43xx_periodic_every30sec(bcm); + bcm43xx_periodic_every15sec(bcm); + bcm->periodic_state = state + 1; + + mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15)); - if (likely(!bcm->shutting_down)) { - queue_delayed_work(bcm->workqueue, &bcm->periodic_work3, - BCM43xx_PERIODIC_3_DELAY); - } spin_unlock_irqrestore(&bcm->lock, flags); } -/* Delete all periodic tasks and make - * sure they are not running any longer - */ static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) { - cancel_delayed_work(&bcm->periodic_work0); - cancel_delayed_work(&bcm->periodic_work1); - cancel_delayed_work(&bcm->periodic_work2); - cancel_delayed_work(&bcm->periodic_work3); - flush_workqueue(bcm->workqueue); + del_timer_sync(&bcm->periodic_tasks); } -/* Setup all periodic tasks. */ static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) { - INIT_WORK(&bcm->periodic_work0, bcm43xx_periodic_work0_handler, bcm); - INIT_WORK(&bcm->periodic_work1, bcm43xx_periodic_work1_handler, bcm); - INIT_WORK(&bcm->periodic_work2, bcm43xx_periodic_work2_handler, bcm); - INIT_WORK(&bcm->periodic_work3, bcm43xx_periodic_work3_handler, bcm); - - /* Periodic task 0: Delay ~15sec */ - queue_delayed_work(bcm->workqueue, &bcm->periodic_work0, - BCM43xx_PERIODIC_0_DELAY); - - /* Periodic task 1: Delay ~60sec */ - queue_delayed_work(bcm->workqueue, &bcm->periodic_work1, - BCM43xx_PERIODIC_1_DELAY); + struct timer_list *timer = &(bcm->periodic_tasks); - /* Periodic task 2: Delay ~120sec */ - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G && - bcm->current_core->phy->rev >= 2) { - queue_delayed_work(bcm->workqueue, &bcm->periodic_work2, - BCM43xx_PERIODIC_2_DELAY); - } - - /* Periodic task 3: Delay ~30sec */ - queue_delayed_work(bcm->workqueue, &bcm->periodic_work3, - BCM43xx_PERIODIC_3_DELAY); + setup_timer(timer, + bcm43xx_periodic_task_handler, + (unsigned long)bcm); + timer->expires = jiffies; + add_timer(timer); } static void bcm43xx_security_init(struct bcm43xx_private *bcm) @@ -3414,13 +3374,13 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) int i, err; unsigned long flags; + bcm43xx_periodic_tasks_delete(bcm); + spin_lock_irqsave(&bcm->lock, flags); bcm->initialized = 0; bcm->shutting_down = 1; spin_unlock_irqrestore(&bcm->lock, flags); - bcm43xx_periodic_tasks_delete(bcm); - for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE)) continue; @@ -4163,13 +4123,11 @@ static int bcm43xx_net_stop(struct net_device *net_dev) static int bcm43xx_init_private(struct bcm43xx_private *bcm, struct net_device *net_dev, - struct pci_dev *pci_dev, - struct workqueue_struct *wq) + struct pci_dev *pci_dev) { bcm->ieee = netdev_priv(net_dev); bcm->softmac = ieee80211_priv(net_dev); bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; - bcm->workqueue = wq; #ifdef DEBUG_ENABLE_MMIO_PRINT bcm43xx_mmioprint_initial(bcm, 1); @@ -4226,7 +4184,6 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, { struct net_device *net_dev; struct bcm43xx_private *bcm; - struct workqueue_struct *wq; int err; #ifdef CONFIG_BCM947XX @@ -4265,20 +4222,15 @@ static int __devinit bcm43xx_init_one(struct pci_dev *pdev, /* initialize the bcm43xx_private struct */ bcm = bcm43xx_priv(net_dev); memset(bcm, 0, sizeof(*bcm)); - wq = create_workqueue(KBUILD_MODNAME "_wq"); - if (!wq) { - err = -ENOMEM; - goto err_free_netdev; - } - err = bcm43xx_init_private(bcm, net_dev, pdev, wq); + err = bcm43xx_init_private(bcm, net_dev, pdev); if (err) - goto err_destroy_wq; + goto err_free_netdev; pci_set_drvdata(pdev, net_dev); err = bcm43xx_attach_board(bcm); if (err) - goto err_destroy_wq; + goto err_free_netdev; err = register_netdev(net_dev); if (err) { @@ -4296,8 +4248,6 @@ out: err_detach_board: bcm43xx_detach_board(bcm); -err_destroy_wq: - destroy_workqueue(wq); err_free_netdev: free_ieee80211softmac(net_dev); goto out; @@ -4312,7 +4262,6 @@ static void __devexit bcm43xx_remove_one(struct pci_dev *pdev) unregister_netdev(net_dev); bcm43xx_detach_board(bcm); assert(bcm->ucode == NULL); - destroy_workqueue(bcm->workqueue); free_ieee80211softmac(net_dev); } @@ -4324,7 +4273,6 @@ static void bcm43xx_chip_reset(void *_bcm) struct bcm43xx_private *bcm = _bcm; struct net_device *net_dev = bcm->net_dev; struct pci_dev *pci_dev = bcm->pci_dev; - struct workqueue_struct *wq = bcm->workqueue; int err; int was_initialized = bcm->initialized; @@ -4336,7 +4284,7 @@ static void bcm43xx_chip_reset(void *_bcm) bcm43xx_free_board(bcm); bcm->firmware_norelease = 0; bcm43xx_detach_board(bcm); - err = bcm43xx_init_private(bcm, net_dev, pci_dev, wq); + err = bcm43xx_init_private(bcm, net_dev, pci_dev); if (err) goto failure; err = bcm43xx_attach_board(bcm); @@ -4364,7 +4312,7 @@ void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); - queue_work(bcm->workqueue, &bcm->restart_work); + schedule_work(&bcm->restart_work); } #ifdef CONFIG_PM -- cgit v1.2.3 From 489423c8d0ba2b4311530502f7b5a331da9a60f9 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 13 Feb 2006 00:11:07 +0100 Subject: [PATCH] bcm43xx: Code cleanups. This removes various "inline" statements and reduces codesize. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 9 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 281 +++++++++++----------------- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 18 +- 3 files changed, 127 insertions(+), 181 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 99b2e72281e..848717513b5 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -19,16 +19,17 @@ #define PFX KBUILD_MODNAME ": " -#define BCM43xx_SWITCH_CORE_MAX_RETRIES 10 +#define BCM43xx_SWITCH_CORE_MAX_RETRIES 50 #define BCM43xx_IRQWAIT_MAX_RETRIES 50 #define BCM43xx_IO_SIZE 8192 -#define BCM43xx_REG_ACTIVE_CORE 0x80 -/* Interrupt Control PCI Configuration Register. (Only on PCI cores with rev >= 6) */ -#define BCM43xx_PCICFG_ICR 0x94 +/* Active Core PCI Configuration Register. */ +#define BCM43xx_PCICFG_ACTIVE_CORE 0x80 /* SPROM control register. */ #define BCM43xx_PCICFG_SPROMCTL 0x88 +/* Interrupt Control PCI Configuration Register. (Only on PCI cores with rev >= 6) */ +#define BCM43xx_PCICFG_ICR 0x94 /* MMIO offsets */ #define BCM43xx_MMIO_DMA1_REASON 0x20 diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 18152b0b2dd..3443bd3c23e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -119,40 +119,29 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging."); //#define DEBUG_ENABLE_PCILOG -static struct pci_device_id bcm43xx_pci_tbl[] = { - - /* Detailed list maintained at: - * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices - */ - -#ifdef CONFIG_BCM947XX - /* SB bus on BCM947xx */ - { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, -#endif - +/* Detailed list maintained at: + * http://openfacts.berlios.de/index-en.phtml?title=Bcm43xxDevices + */ + static struct pci_device_id bcm43xx_pci_tbl[] = { /* Broadcom 4303 802.11b */ { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - - /* Broadcom 4307 802.11b */ + /* Broadcom 4307 802.11b */ { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - - /* Broadcom 4318 802.11b/g */ + /* Broadcom 4318 802.11b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 4306 802.11b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - - /* Broadcom 4306 802.11a */ + /* Broadcom 4306 802.11a */ // { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 4309 802.11a/b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - /* Broadcom 43XG 802.11b/g */ { PCI_VENDOR_ID_BROADCOM, 0x4325, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - - /* required last entry */ - { 0, }, +#ifdef CONFIG_BCM947XX + /* SB bus on BCM947xx */ + { PCI_VENDOR_ID_BROADCOM, 0x0800, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, +#endif + { 0 }, }; MODULE_DEVICE_TABLE(pci, bcm43xx_pci_tbl); @@ -353,9 +342,8 @@ void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); } -static inline -u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp, - const int ofdm_modulation) +static u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp, + const int ofdm_modulation) { u8 rate; @@ -412,8 +400,7 @@ u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp, return rate; } -static inline -u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) +static u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) { switch (bitrate) { case IEEE80211_CCK_RATE_1MB: @@ -429,8 +416,7 @@ u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) return 0; } -static inline -u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) +static u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) { switch (bitrate) { case IEEE80211_OFDM_RATE_6MB: @@ -489,13 +475,12 @@ static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp, //bcm43xx_printk_bitdump(raw, 4, 0, "PLCP"); } -void fastcall -bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, - struct bcm43xx_txhdr *txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, - const int is_first_fragment, - const u16 cookie) +void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie) { const struct bcm43xx_phyinfo *phy = bcm->current_core->phy; const struct ieee80211_hdr_1addr *wireless_header = (const struct ieee80211_hdr_1addr *)fragment_data; @@ -606,9 +591,8 @@ void bcm43xx_macfilter_set(struct bcm43xx_private *bcm, bcm43xx_write16(bcm, BCM43xx_MMIO_MACFILTER_DATA, data); } -static inline -void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm, - u16 offset) +static void bcm43xx_macfilter_clear(struct bcm43xx_private *bcm, + u16 offset) { const u8 zero_addr[ETH_ALEN] = { 0 }; @@ -634,8 +618,7 @@ static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm) bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i))); } -static inline -void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) +static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) { /* slot_time is in usec. */ if (bcm->current_core->phy->type != BCM43xx_PHYTYPE_G) @@ -644,14 +627,12 @@ void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time); } -static inline -void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm) +static void bcm43xx_short_slot_timing_enable(struct bcm43xx_private *bcm) { bcm43xx_set_slot_time(bcm, 9); } -static inline -void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm) +static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm) { bcm43xx_set_slot_time(bcm, 20); } @@ -744,6 +725,8 @@ static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *old static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) { + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; u32 radio_id; u16 manufact; u16 version; @@ -769,10 +752,10 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) version = (radio_id & 0x0FFFF000) >> 12; revision = (radio_id & 0xF0000000) >> 28; - dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n", + dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n", radio_id, manufact, version, revision); - switch (bcm->current_core->phy->type) { + switch (phy->type) { case BCM43xx_PHYTYPE_A: if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f)) goto err_unsupported_radio; @@ -787,25 +770,25 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) break; } - bcm->current_core->radio->manufact = manufact; - bcm->current_core->radio->version = version; - bcm->current_core->radio->revision = revision; + radio->manufact = manufact; + radio->version = version; + radio->revision = revision; /* Set default attenuation values. */ - bcm->current_core->radio->txpower[0] = 2; - bcm->current_core->radio->txpower[1] = 2; + radio->txpower[0] = 2; + radio->txpower[1] = 2; if (revision == 1) - bcm->current_core->radio->txpower[2] = 3; + radio->txpower[2] = 3; else - bcm->current_core->radio->txpower[2] = 0; + radio->txpower[2] = 0; if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) - bcm->current_core->radio->txpower_desired = bcm->sprom.maxpower_aphy; + radio->txpower_desired = bcm->sprom.maxpower_aphy; else bcm->current_core->radio->txpower_desired = bcm->sprom.maxpower_bgphy; /* Initialize the in-memory nrssi Lookup Table. */ for (i = 0; i < 64; i++) - bcm->current_core->radio->nrssi_lt[i] = i; + radio->nrssi_lt[i] = i; return 0; @@ -1155,6 +1138,7 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) */ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) { + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; unsigned int i, max_loop; u16 value = 0; u32 buffer[5] = { @@ -1165,7 +1149,7 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) 0x00000000, }; - switch (bcm->current_core->phy->type) { + switch (phy->type) { case BCM43xx_PHYTYPE_A: max_loop = 0x1E; buffer[0] = 0xCC010200; @@ -1187,7 +1171,7 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) bcm43xx_write16(bcm, 0x0568, 0x0000); bcm43xx_write16(bcm, 0x07C0, 0x0000); - bcm43xx_write16(bcm, 0x050C, ((bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0)); + bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0)); bcm43xx_write16(bcm, 0x0508, 0x0000); bcm43xx_write16(bcm, 0x050A, 0x0000); bcm43xx_write16(bcm, 0x054C, 0x0000); @@ -1324,25 +1308,6 @@ static void bcm43xx_clear_keys(struct bcm43xx_private *bcm) dprintk(KERN_INFO PFX "Keys cleared\n"); } -/* Puts the index of the current core into user supplied core variable. - * This function reads the value from the device. - * Almost always you don't want to call this, but use bcm->current_core - */ -static inline -int _get_current_core(struct bcm43xx_private *bcm, int *core) -{ - int err; - - err = bcm43xx_pci_read_config32(bcm, BCM43xx_REG_ACTIVE_CORE, core); - if (unlikely(err)) { - dprintk(KERN_ERR PFX "BCM43xx_REG_ACTIVE_CORE read failed!\n"); - return -ENODEV; - } - *core = (*core - 0x18000000) / 0x1000; - - return 0; -} - /* Lowlevel core-switch function. This is only to be used in * bcm43xx_switch_core() and bcm43xx_probe_cores() */ @@ -1350,63 +1315,57 @@ static int _switch_core(struct bcm43xx_private *bcm, int core) { int err; int attempts = 0; - int current_core = -1; + u32 current_core; assert(core >= 0); - - err = _get_current_core(bcm, ¤t_core); - if (unlikely(err)) - goto out; - - /* Write the computed value to the register. This doesn't always - succeed so we retry BCM43xx_SWITCH_CORE_MAX_RETRIES times */ - while (current_core != core) { - if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES)) { - err = -ENODEV; - printk(KERN_ERR PFX - "unable to switch to core %u, retried %i times\n", - core, attempts); - goto out; - } - err = bcm43xx_pci_write_config32(bcm, BCM43xx_REG_ACTIVE_CORE, + while (1) { + err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE, (core * 0x1000) + 0x18000000); - if (unlikely(err)) { - dprintk(KERN_ERR PFX "BCM43xx_REG_ACTIVE_CORE write failed!\n"); - continue; - } - _get_current_core(bcm, ¤t_core); + if (unlikely(err)) + goto error; + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE, + ¤t_core); + if (unlikely(err)) + goto error; + current_core = (current_core - 0x18000000) / 0x1000; + if (current_core == core) + break; + + if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES)) + goto error; + udelay(10); + } #ifdef CONFIG_BCM947XX - if (bcm->pci_dev->bus->number == 0) - bcm->current_core_offset = 0x1000 * core; - else - bcm->current_core_offset = 0; + if (bcm->pci_dev->bus->number == 0) + bcm->current_core_offset = 0x1000 * core; + else + bcm->current_core_offset = 0; #endif - } - assert(err == 0); -out: - return err; + return 0; +error: + printk(KERN_ERR PFX "Failed to switch to core %d\n", core); + return -ENODEV; } int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core) { int err; - if (!new_core) + if (unlikely(!new_core)) return 0; - if (!(new_core->flags & BCM43xx_COREFLAG_AVAILABLE)) return -ENODEV; if (bcm->current_core == new_core) return 0; err = _switch_core(bcm, new_core->index); - if (!err) + if (likely(!err)) bcm->current_core = new_core; return err; } -static inline int bcm43xx_core_enabled(struct bcm43xx_private *bcm) +static int bcm43xx_core_enabled(struct bcm43xx_private *bcm) { u32 value; @@ -1609,7 +1568,7 @@ out: return err; } -static inline void handle_irq_transmit_status(struct bcm43xx_private *bcm) +static void handle_irq_transmit_status(struct bcm43xx_private *bcm) { u32 v0, v1; u16 tmp; @@ -1648,7 +1607,7 @@ static inline void handle_irq_transmit_status(struct bcm43xx_private *bcm) } } -static inline void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm) +static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm) { bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F); @@ -1672,7 +1631,7 @@ static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm) bcm43xx_generate_noise_sample(bcm); } -static inline void handle_irq_noise(struct bcm43xx_private *bcm) +static void handle_irq_noise(struct bcm43xx_private *bcm) { struct bcm43xx_radioinfo *radio = bcm->current_core->radio; u16 tmp; @@ -1747,8 +1706,7 @@ generate_new: bcm43xx_generate_noise_sample(bcm); } -static inline -void handle_irq_ps(struct bcm43xx_private *bcm) +static void handle_irq_ps(struct bcm43xx_private *bcm) { if (bcm->ieee->iw_mode == IW_MODE_MASTER) { ///TODO: PS TBTT @@ -1761,8 +1719,7 @@ void handle_irq_ps(struct bcm43xx_private *bcm) //FIXME else set to false? } -static inline -void handle_irq_reg124(struct bcm43xx_private *bcm) +static void handle_irq_reg124(struct bcm43xx_private *bcm) { if (!bcm->reg124_set_0x4) return; @@ -1772,8 +1729,7 @@ void handle_irq_reg124(struct bcm43xx_private *bcm) //FIXME: reset reg124_set_0x4 to false? } -static inline -void handle_irq_pmq(struct bcm43xx_private *bcm) +static void handle_irq_pmq(struct bcm43xx_private *bcm) { u32 tmp; @@ -1829,8 +1785,7 @@ static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm, bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size); } -static inline -void handle_irq_beacon(struct bcm43xx_private *bcm) +static void handle_irq_beacon(struct bcm43xx_private *bcm) { u32 status; @@ -1992,9 +1947,8 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) #undef bcmirq_print_reasons -static inline -void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, - u32 reason, u32 mask) +static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, + u32 reason, u32 mask) { bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) & 0x0001dc00; @@ -2340,7 +2294,7 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) SA_SHIRQ, KBUILD_MODNAME, bcm); if (res) { printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); - return -EFAULT; + return -ENODEV; } bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff); bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); @@ -2367,7 +2321,7 @@ static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm) /* Switch to the core used to write the GPIO register. * This is either the ChipCommon, or the PCI core. */ -static inline int switch_to_gpio_core(struct bcm43xx_private *bcm) +static int switch_to_gpio_core(struct bcm43xx_private *bcm) { int err; @@ -2379,13 +2333,13 @@ static inline int switch_to_gpio_core(struct bcm43xx_private *bcm) err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); if (err == -ENODEV) { err = bcm43xx_switch_core(bcm, &bcm->core_pci); - if (err == -ENODEV) { + if (unlikely(err == -ENODEV)) { printk(KERN_ERR PFX "gpio error: " "Neither ChipCommon nor PCI core available!\n"); return -ENODEV; - } else if (err != 0) + } else if (unlikely(err != 0)) return -ENODEV; - } else if (err != 0) + } else if (unlikely(err != 0)) return -ENODEV; return 0; @@ -2691,40 +2645,30 @@ err_release_fw: * http://bcm-specs.sipsolutions.net/ValidateChipAccess */ static int bcm43xx_validate_chip(struct bcm43xx_private *bcm) { - int err = -ENODEV; u32 value; u32 shm_backup; shm_backup = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000); bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0xAA5555AA); - if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA) { - printk(KERN_ERR PFX "Error: SHM mismatch (1) validating chip\n"); - goto out; - } - + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0xAA5555AA) + goto error; bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, 0x55AAAA55); - if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55) { - printk(KERN_ERR PFX "Error: SHM mismatch (2) validating chip\n"); - goto out; - } - + if (bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, 0x0000) != 0x55AAAA55) + goto error; bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, 0x0000, shm_backup); value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - if ((value | 0x80000000) != 0x80000400) { - printk(KERN_ERR PFX "Error: Bad Status Bitfield while validating chip\n"); - goto out; - } + if ((value | 0x80000000) != 0x80000400) + goto error; value = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); - if (value != 0x00000000) { - printk(KERN_ERR PFX "Error: Bad interrupt reason code while validating chip\n"); - goto out; - } + if (value != 0x00000000) + goto error; - err = 0; -out: - return err; + return 0; +error: + printk(KERN_ERR PFX "Failed to validate the chipaccess\n"); + return -ENODEV; } static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) @@ -3172,9 +3116,9 @@ static void bcm43xx_chipset_detach(struct bcm43xx_private *bcm) bcm43xx_pctl_set_crystal(bcm, 0); } -static inline void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm, - u32 address, - u32 data) +static void bcm43xx_pcicore_broadcast_value(struct bcm43xx_private *bcm, + u32 address, + u32 data) { bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_ADDR, address); bcm43xx_write32(bcm, BCM43xx_PCICORE_BCAST_DATA, data); @@ -3523,6 +3467,7 @@ static void bcm43xx_detach_board(struct bcm43xx_private *bcm) static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) { + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; u16 value; u8 phy_version; u8 phy_type; @@ -3578,15 +3523,15 @@ static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) phy_rev); } - bcm->current_core->phy->version = phy_version; - bcm->current_core->phy->type = phy_type; - bcm->current_core->phy->rev = phy_rev; + phy->version = phy_version; + phy->type = phy_type; + phy->rev = phy_rev; if ((phy_type == BCM43xx_PHYTYPE_B) || (phy_type == BCM43xx_PHYTYPE_G)) { p = kzalloc(sizeof(struct bcm43xx_lopair) * BCM43xx_LO_COUNT, GFP_KERNEL); if (!p) return -ENOMEM; - bcm->current_core->phy->_lo_pairs = p; + phy->_lo_pairs = p; } return 0; @@ -3757,9 +3702,9 @@ err_pci_disable: goto out; } -static inline -s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, u8 in_rssi, - int ofdm, int adjust_2053, int adjust_2050) +static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, + u8 in_rssi, int ofdm, + int adjust_2053, int adjust_2050) { s32 tmp; @@ -3816,8 +3761,8 @@ s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, u8 in_rssi, return (s8)tmp; } -static inline -s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, u8 in_rssi) +static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, + u8 in_rssi) { s8 ret; @@ -3843,9 +3788,9 @@ int bcm43xx_rx_packet(struct bcm43xx_private *bcm, return 0; } -int fastcall bcm43xx_rx(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct bcm43xx_rxhdr *rxhdr) +int bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr) { struct bcm43xx_plcp_hdr4 *plcp; struct ieee80211_rx_stats stats; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index 1d3eddd314b..298e24b4ab6 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -111,12 +111,12 @@ struct bcm43xx_txhdr { struct sk_buff; -void FASTCALL(bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, - struct bcm43xx_txhdr *txhdr, - const unsigned char *fragment_data, - const unsigned int fragment_len, - const int is_first_fragment, - const u16 cookie)); +void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + const unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie); /* RX header as received from the hardware. */ struct bcm43xx_rxhdr { @@ -244,9 +244,9 @@ int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf); void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf); -int FASTCALL(bcm43xx_rx(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct bcm43xx_rxhdr *rxhdr)); +int bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr); void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, int iw_mode); -- cgit v1.2.3 From ea0922b067a0863f9a4198740651fd47a22af7f1 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 19 Feb 2006 14:09:20 +0100 Subject: [PATCH] bcm43xx: Move sprom lowlevel reading/writing to its own functions. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 93 ++++++++++++++++++++++++----- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 3 + drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 66 ++------------------ 3 files changed, 86 insertions(+), 76 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 3443bd3c23e..bcbd009a533 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -916,13 +916,84 @@ u8 bcm43xx_sprom_crc(const u16 *sprom) return crc; } - -static int bcm43xx_read_sprom(struct bcm43xx_private *bcm) +int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom) { int i; + u8 crc, expected_crc; + + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) + sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2)); + /* CRC-8 check. */ + crc = bcm43xx_sprom_crc(sprom); + expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; + if (crc != expected_crc) { + printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum " + "(0x%02X, expected: 0x%02X)\n", + crc, expected_crc); + return -EINVAL; + } + + return 0; +} + +int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom) +{ + int i, err; + u8 crc, expected_crc; + u32 spromctl; + + /* CRC-8 validation of the input data. */ + crc = bcm43xx_sprom_crc(sprom); + expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; + if (crc != expected_crc) { + printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n"); + return -EINVAL; + } + + printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); + err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl); + if (err) + goto err_ctlreg; + spromctl |= 0x10; /* SPROM WRITE enable. */ + bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); + if (err) + goto err_ctlreg; + /* We must burn lots of CPU cycles here, but that does not + * really matter as one does not write the SPROM every other minute... + */ + printk(KERN_INFO PFX "[ 0%%"); + mdelay(500); + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + if (i == 16) + printk("25%%"); + else if (i == 32) + printk("50%%"); + else if (i == 48) + printk("75%%"); + else if (i % 2) + printk("."); + bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); + mdelay(20); + } + spromctl &= ~0x10; /* SPROM WRITE enable. */ + bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); + if (err) + goto err_ctlreg; + mdelay(500); + printk("100%% ]\n"); + printk(KERN_INFO PFX "SPROM written.\n"); + bcm43xx_controller_restart(bcm, "SPROM update"); + + return 0; +err_ctlreg: + printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + return -ENODEV; +} + +static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm) +{ u16 value; u16 *sprom; - u8 crc, expected_crc; #ifdef CONFIG_BCM947XX char *c; #endif @@ -930,7 +1001,7 @@ static int bcm43xx_read_sprom(struct bcm43xx_private *bcm) sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16), GFP_KERNEL); if (!sprom) { - printk(KERN_ERR PFX "read_sprom OOM\n"); + printk(KERN_ERR PFX "sprom_extract OOM\n"); return -ENOMEM; } #ifdef CONFIG_BCM947XX @@ -953,17 +1024,7 @@ static int bcm43xx_read_sprom(struct bcm43xx_private *bcm) sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev")); #else - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) - sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2)); - - /* CRC-8 check. */ - crc = bcm43xx_sprom_crc(sprom); - expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; - if (crc != expected_crc) { - printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum " - "(0x%02X, expected: 0x%02X)\n", - crc, expected_crc); - } + bcm43xx_sprom_read(bcm, sprom); #endif /* boardflags2 */ @@ -3632,7 +3693,7 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) goto err_chipset_detach; } - err = bcm43xx_read_sprom(bcm); + err = bcm43xx_sprom_extract(bcm); if (err) goto err_chipset_detach; err = bcm43xx_leds_init(bcm); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index 298e24b4ab6..0c4bd08568c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -280,4 +280,7 @@ u8 bcm43xx_sprom_crc(const u16 *sprom); void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); +int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom); +int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom); + #endif /* BCM43xx_MAIN_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 4c972cdc0a2..df37d28996c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -782,7 +782,6 @@ static int hex2sprom(u16 *sprom, const char *dump, unsigned int len) char tmp[5] = { 0 }; int cnt = 0; unsigned long parsed; - u8 crc, expected_crc; if (len < BCM43xx_SPROM_SIZE * sizeof(u16) * 2) return -EINVAL; @@ -793,13 +792,6 @@ static int hex2sprom(u16 *sprom, const char *dump, unsigned int len) sprom[cnt++] = swab16((u16)parsed); } - crc = bcm43xx_sprom_crc(sprom); - expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8; - if (crc != expected_crc) { - printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n"); - return -EINVAL; - } - return 0; } @@ -809,7 +801,7 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev, char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - int err = -EPERM, i; + int err = -EPERM; u16 *sprom; unsigned long flags; @@ -828,13 +820,10 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev, spin_unlock_irqrestore(&bcm->lock, flags); goto out_kfree; } - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) - sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2)); + err = bcm43xx_sprom_read(bcm, sprom); spin_unlock_irqrestore(&bcm->lock, flags); - - data->data.length = sprom2hex(sprom, extra); - - err = 0; + if (!err) + data->data.length = sprom2hex(sprom, extra); out_kfree: kfree(sprom); out: @@ -852,8 +841,6 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev, unsigned long flags; char *input; unsigned int len; - u32 spromctl; - int i; if (!capable(CAP_SYS_RAWIO)) goto out; @@ -878,50 +865,9 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev, spin_lock_irqsave(&bcm->lock, flags); err = -ENODEV; - if (!bcm->initialized) { - spin_unlock_irqrestore(&bcm->lock, flags); - goto out_kfree; - } - - printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n"); - err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl); - if (err) { - printk(KERN_ERR PFX "Could not access SPROM control register.\n"); - goto out_unlock; - } - spromctl |= 0x10; /* SPROM WRITE enable. */ - bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); - if (err) { - printk(KERN_ERR PFX "Could not access SPROM control register.\n"); - goto out_unlock; - } - /* We must burn lots of CPU cycles here, but that does not - * really matter as one does not write the SPROM every other minute... - */ - printk(KERN_INFO PFX "[ 0%%"); - mdelay(500); - for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { - if (i == 16) - printk("25%%"); - else if (i == 32) - printk("50%%"); - else if (i == 48) - printk("75%%"); - else if (i % 2) - printk("."); - bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); - mdelay(20); - } - spromctl &= ~0x10; /* SPROM WRITE enable. */ - bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl); - if (err) { - printk(KERN_ERR PFX "Could not access SPROM control register.\n"); + if (!bcm->initialized) goto out_unlock; - } - mdelay(500); - printk("100%% ]\n"); - printk(KERN_INFO PFX "SPROM written.\n"); - err = 0; + err = bcm43xx_sprom_write(bcm, sprom); out_unlock: spin_unlock_irqrestore(&bcm->lock, flags); out_kfree: -- cgit v1.2.3 From ad3f086c49aa682e493c935cda76f3850ee4a80e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 19 Feb 2006 14:12:22 +0100 Subject: [PATCH] bcm43xx: make bcm43xx_sprom_crc() static. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index bcbd009a533..b4767e42e8f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -901,7 +901,7 @@ static inline u8 bcm43xx_crc8(u8 crc, u8 data) return t[crc ^ data]; } -u8 bcm43xx_sprom_crc(const u16 *sprom) +static u8 bcm43xx_sprom_crc(const u16 *sprom) { int word; u8 crc = 0xFF; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index 0c4bd08568c..0a22e833915 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -276,8 +276,6 @@ int bcm43xx_pci_write_config_32(struct pci_dev *pdev, int offset, u32 val); void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); void bcm43xx_mac_enable(struct bcm43xx_private *bcm); -u8 bcm43xx_sprom_crc(const u16 *sprom); - void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason); int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom); -- cgit v1.2.3 From 10d8dd88dcc2c8ebe8ac7dcf75a2da7c9f9ee0f3 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 19 Feb 2006 22:08:48 +0100 Subject: [PATCH] bcm43xx: split the channel helper functions, so that they can be used without a valid running core. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 +- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 80 ++++++++++++++++++----------- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 12 +++-- 3 files changed, 59 insertions(+), 37 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index b4767e42e8f..6195c2a1516 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1169,7 +1169,7 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) if (have_a) { for (i = 0, channel = 0; channel < 201; channel++) { chan = &geo.a[i++]; - chan->freq = bcm43xx_channel_to_freq(bcm, channel); + chan->freq = bcm43xx_channel_to_freq_a(channel); chan->channel = channel; } geo.a_channels = i; @@ -1177,7 +1177,7 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) if (have_bg) { for (i = 0, channel = 1; channel < 15; channel++) { chan = &geo.bg[i++]; - chan->freq = bcm43xx_channel_to_freq(bcm, channel); + chan->freq = bcm43xx_channel_to_freq_bg(channel); chan->channel = channel; } geo.bg_channels = i; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index 0a22e833915..7d696d257f7 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -187,58 +187,78 @@ struct bcm43xx_xmitstatus_queue { /* Lightweight function to convert a frequency (in Mhz) to a channel number. */ static inline -u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm, - int freq) +u8 bcm43xx_freq_to_channel_a(int freq) +{ + return ((freq - 5000) / 5); +} +static inline +u8 bcm43xx_freq_to_channel_bg(int freq) { u8 channel; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { - channel = (freq - 5000) / 5; - } else { - if (freq == 2484) - channel = 14; - else - channel = (freq - 2407) / 5; - } + if (freq == 2484) + channel = 14; + else + channel = (freq - 2407) / 5; return channel; } +static inline +u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm, + int freq) +{ + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + return bcm43xx_freq_to_channel_a(freq); + return bcm43xx_freq_to_channel_bg(freq); +} /* Lightweight function to convert a channel number to a frequency (in Mhz). */ static inline -int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm, - u8 channel) +int bcm43xx_channel_to_freq_a(u8 channel) +{ + return (5000 + (5 * channel)); +} +static inline +int bcm43xx_channel_to_freq_bg(u8 channel) { int freq; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { - freq = 5000 + (5 * channel); - } else { - if (channel == 14) - freq = 2484; - else - freq = 2407 + (5 * channel); - } + if (channel == 14) + freq = 2484; + else + freq = 2407 + (5 * channel); return freq; } +static inline +int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm, + u8 channel) +{ + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + return bcm43xx_channel_to_freq_a(channel); + return bcm43xx_channel_to_freq_bg(channel); +} /* Lightweight function to check if a channel number is valid. * Note that this does _NOT_ check for geographical restrictions! */ static inline +int bcm43xx_is_valid_channel_a(u8 channel) +{ + return (channel <= 200); +} +static inline +int bcm43xx_is_valid_channel_bg(u8 channel) +{ + return (channel >= 1 && channel <= 14); +} +static inline int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, - u8 channel) + u8 channel) { - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { - if (channel <= 200) - return 1; - } else { - if (channel >= 1 && channel <= 14) - return 1; - } - - return 0; + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + return bcm43xx_is_valid_channel_a(channel); + return bcm43xx_is_valid_channel_bg(channel); } void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index df37d28996c..aa2d9930c43 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -111,8 +111,9 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, unsigned long flags; u8 channel; int freq; - int err = 0; + int err = -EINVAL; + spin_lock_irqsave(&bcm->lock, flags); if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { channel = data->freq.m; freq = bcm43xx_channel_to_freq(bcm, channel); @@ -121,16 +122,17 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, freq = data->freq.m; } if (!bcm43xx_is_valid_channel(bcm, channel)) - return -EINVAL; - - spin_lock_irqsave(&bcm->lock, flags); + goto out_unlock; if (bcm->initialized) { //ieee80211softmac_disassoc(softmac, $REASON); bcm43xx_mac_suspend(bcm); err = bcm43xx_radio_selectchannel(bcm, channel, 0); bcm43xx_mac_enable(bcm); - } else + } else { bcm->current_core->radio->initial_channel = channel; + err = 0; + } +out_unlock: spin_unlock_irqrestore(&bcm->lock, flags); return err; -- cgit v1.2.3 From 26533e7e292075df1daf94965a7f3f0d91bd08a8 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 19 Feb 2006 22:25:09 +0100 Subject: [PATCH] bcm43xx: remove old unused struct. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index 7d696d257f7..d460393ed34 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -179,11 +179,6 @@ struct bcm43xx_xmitstatus { //TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40 //TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80 -struct bcm43xx_xmitstatus_queue { - struct list_head list; - struct bcm43xx_hwxmitstatus status; -}; - /* Lightweight function to convert a frequency (in Mhz) to a channel number. */ static inline -- cgit v1.2.3 From c4c3beb7d70ae9d1fe97b7b49bc5a10ad26c2b01 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 20 Feb 2006 22:48:55 +0100 Subject: [PATCH] bcm43xx: Fix Kconfig typo (transfer mode default) Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/Kconfig b/drivers/net/wireless/bcm43xx/Kconfig index 1d677c15b21..418465600a7 100644 --- a/drivers/net/wireless/bcm43xx/Kconfig +++ b/drivers/net/wireless/bcm43xx/Kconfig @@ -23,7 +23,7 @@ config BCM43XX_PIO choice prompt "BCM43xx data transfer mode" depends on BCM43XX - default BCM43XX_DMA_AND_PIO + default BCM43XX_DMA_AND_PIO_MODE config BCM43XX_DMA_AND_PIO_MODE bool "DMA + PIO" -- cgit v1.2.3 From bf7b876043e6e1390b1234d740f4fd9af20b3b9e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 21 Feb 2006 17:58:18 +0100 Subject: [PATCH] bcm43xx: Workaround init_board vs IRQ race. The proper fix for this is to move IRQ enabling to the end of init_board. But this is nontrivial and needs to be done with care. Stay with this cheap workaround for now. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 6195c2a1516..57306a65840 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2079,12 +2079,19 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re bcm43xx_interrupt_ack(bcm, reason, mask); - /* disable all IRQs. They are enabled again in the bottom half. */ - bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); - - /* save the reason code and call our bottom half. */ - bcm->irq_reason = reason; - tasklet_schedule(&bcm->isr_tasklet); + /* Only accept IRQs, if we are initialized properly. + * This avoids an RX race while initializing. + * We should probably not enable IRQs before we are initialized + * completely, but some careful work is needed to fix this. I think it + * is best to stay with this cheap workaround for now... . + */ + if (likely(bcm->initialized)) { + /* disable all IRQs. They are enabled again in the bottom half. */ + bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + /* save the reason code and call our bottom half. */ + bcm->irq_reason = reason; + tasklet_schedule(&bcm->isr_tasklet); + } spin_unlock(&bcm->lock); -- cgit v1.2.3 From cad2b31a76763d06048fb23a17b062acd5d46639 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 21 Feb 2006 18:08:55 +0100 Subject: [PATCH] bcm43xx: move initialized = 1 to the end of init_board. Note that the periodic work has to be started with initialized==1 Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 57306a65840..4a7d88d2821 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3484,15 +3484,17 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); - spin_lock_irqsave(&bcm->lock, flags); - bcm->initialized = 1; - spin_unlock_irqrestore(&bcm->lock, flags); - if (bcm->current_core->radio->initial_channel != 0xFF) { bcm43xx_mac_suspend(bcm); bcm43xx_radio_selectchannel(bcm, bcm->current_core->radio->initial_channel, 0); bcm43xx_mac_enable(bcm); } + + /* Initialization of the board is done. Flag it as such. */ + spin_lock_irqsave(&bcm->lock, flags); + bcm->initialized = 1; + spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_periodic_tasks_setup(bcm); assert(err == 0); -- cgit v1.2.3 From 1d1a73ccdc618168f2a5c962aab250605c93e517 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 21 Feb 2006 18:19:59 +0100 Subject: [PATCH] bcm43xx: add assert(bcm->initialized) to periodic_tasks_setup(). Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 4a7d88d2821..899c06fe0bf 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3366,6 +3366,7 @@ static void bcm43xx_periodic_tasks_setup(struct bcm43xx_private *bcm) { struct timer_list *timer = &(bcm->periodic_tasks); + assert(bcm->initialized); setup_timer(timer, bcm43xx_periodic_task_handler, (unsigned long)bcm); -- cgit v1.2.3 From f398f02d12cdc372e16c5e86246b10acf7211abc Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Thu, 23 Feb 2006 21:15:39 +0100 Subject: [PATCH] bcm43xx: Move TX/RX related functions to its own file. Add basic RTS/CTS code. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/Makefile | 1 + drivers/net/wireless/bcm43xx/bcm43xx.h | 23 +- drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 1 + drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 1 + drivers/net/wireless/bcm43xx/bcm43xx_main.c | 430 +----------------- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 131 ------ drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 1 + drivers/net/wireless/bcm43xx/bcm43xx_xmit.c | 579 +++++++++++++++++++++++++ drivers/net/wireless/bcm43xx/bcm43xx_xmit.h | 156 +++++++ 9 files changed, 746 insertions(+), 577 deletions(-) create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_xmit.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_xmit.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile index c87c1525b39..2962b5f9e3e 100644 --- a/drivers/net/wireless/bcm43xx/Makefile +++ b/drivers/net/wireless/bcm43xx/Makefile @@ -8,4 +8,5 @@ bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \ bcm43xx_radio.o bcm43xx_phy.o \ bcm43xx_power.o bcm43xx_wx.o \ bcm43xx_leds.o bcm43xx_ethtool.o \ + bcm43xx_xmit.o \ $(bcm43xx-obj-y) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 848717513b5..21c75cae14b 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -314,23 +314,6 @@ /* Initial default iw_mode */ #define BCM43xx_INITIAL_IWMODE IW_MODE_INFRA -/* Values/Masks for the device TX header */ -#define BCM43xx_TXHDRFLAG_EXPECTACK 0x0001 -#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT 0x0008 -#define BCM43xx_TXHDRFLAG_DESTPSMODE 0x0020 -#define BCM43xx_TXHDRFLAG_FALLBACKOFDM 0x0100 -#define BCM43xx_TXHDRFLAG_FRAMEBURST 0x0800 - -#define BCM43xx_TXHDRCTL_OFDM 0x0001 -#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE 0x0010 -#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK 0x0030 -#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT 8 - -#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK 0x00F0 -#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT 4 -#define BCM43xx_TXHDR_WSEC_ALGO_MASK 0x0003 -#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT 0 - /* Bus type PCI. */ #define BCM43xx_BUSTYPE_PCI 0 /* Bus type Silicone Backplane Bus. */ @@ -952,4 +935,10 @@ int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 valu __value; \ }) +/** Helpers to print MAC addresses. */ +#define BCM43xx_MACFMT "%02x:%02x:%02x:%02x:%02x:%02x" +#define BCM43xx_MACARG(x) ((u8*)(x))[0], ((u8*)(x))[1], \ + ((u8*)(x))[2], ((u8*)(x))[3], \ + ((u8*)(x))[4], ((u8*)(x))[5] + #endif /* BCM43xx_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index 5a7dc43cd67..0bae0be4be2 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -37,6 +37,7 @@ #include "bcm43xx_debugfs.h" #include "bcm43xx_dma.h" #include "bcm43xx_pio.h" +#include "bcm43xx_xmit.h" #define REALLY_BIG_BUFFER_SIZE (1024*256) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index af5c27f9bfd..e20fbaf29e0 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -32,6 +32,7 @@ #include "bcm43xx_main.h" #include "bcm43xx_debugfs.h" #include "bcm43xx_power.h" +#include "bcm43xx_xmit.h" #include #include diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 899c06fe0bf..f1ac9940f14 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -50,6 +50,7 @@ #include "bcm43xx_power.h" #include "bcm43xx_wx.h" #include "bcm43xx_ethtool.h" +#include "bcm43xx_xmit.h" MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver"); @@ -342,234 +343,6 @@ void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); } -static u8 bcm43xx_plcp_get_bitrate(struct bcm43xx_plcp_hdr4 *plcp, - const int ofdm_modulation) -{ - u8 rate; - - if (ofdm_modulation) { - switch (plcp->raw[0] & 0xF) { - case 0xB: - rate = IEEE80211_OFDM_RATE_6MB; - break; - case 0xF: - rate = IEEE80211_OFDM_RATE_9MB; - break; - case 0xA: - rate = IEEE80211_OFDM_RATE_12MB; - break; - case 0xE: - rate = IEEE80211_OFDM_RATE_18MB; - break; - case 0x9: - rate = IEEE80211_OFDM_RATE_24MB; - break; - case 0xD: - rate = IEEE80211_OFDM_RATE_36MB; - break; - case 0x8: - rate = IEEE80211_OFDM_RATE_48MB; - break; - case 0xC: - rate = IEEE80211_OFDM_RATE_54MB; - break; - default: - rate = 0; - assert(0); - } - } else { - switch (plcp->raw[0]) { - case 0x0A: - rate = IEEE80211_CCK_RATE_1MB; - break; - case 0x14: - rate = IEEE80211_CCK_RATE_2MB; - break; - case 0x37: - rate = IEEE80211_CCK_RATE_5MB; - break; - case 0x6E: - rate = IEEE80211_CCK_RATE_11MB; - break; - default: - rate = 0; - assert(0); - } - } - - return rate; -} - -static u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) -{ - switch (bitrate) { - case IEEE80211_CCK_RATE_1MB: - return 0x0A; - case IEEE80211_CCK_RATE_2MB: - return 0x14; - case IEEE80211_CCK_RATE_5MB: - return 0x37; - case IEEE80211_CCK_RATE_11MB: - return 0x6E; - } - assert(0); - return 0; -} - -static u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) -{ - switch (bitrate) { - case IEEE80211_OFDM_RATE_6MB: - return 0xB; - case IEEE80211_OFDM_RATE_9MB: - return 0xF; - case IEEE80211_OFDM_RATE_12MB: - return 0xA; - case IEEE80211_OFDM_RATE_18MB: - return 0xE; - case IEEE80211_OFDM_RATE_24MB: - return 0x9; - case IEEE80211_OFDM_RATE_36MB: - return 0xD; - case IEEE80211_OFDM_RATE_48MB: - return 0x8; - case IEEE80211_OFDM_RATE_54MB: - return 0xC; - } - assert(0); - return 0; -} - -static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp, - u16 octets, const u8 bitrate, - const int ofdm_modulation) -{ - __le32 *data = &(plcp->data); - __u8 *raw = plcp->raw; - - /* Account for hardware-appended FCS. */ - octets += IEEE80211_FCS_LEN; - - if (ofdm_modulation) { - *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate); - assert(!(octets & 0xF000)); - *data |= (octets << 5); - *data = cpu_to_le32(*data); - } else { - u32 plen; - - plen = octets * 16 / bitrate; - if ((octets * 16 % bitrate) > 0) { - plen++; - if ((bitrate == IEEE80211_CCK_RATE_11MB) - && ((octets * 8 % 11) < 4)) { - raw[1] = 0x84; - } else - raw[1] = 0x04; - } else - raw[1] = 0x04; - *data |= cpu_to_le32(plen << 16); - raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate); - } - -//bcm43xx_printk_bitdump(raw, 4, 0, "PLCP"); -} - -void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, - struct bcm43xx_txhdr *txhdr, - const unsigned char *fragment_data, - unsigned int fragment_len, - const int is_first_fragment, - const u16 cookie) -{ - const struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - const struct ieee80211_hdr_1addr *wireless_header = (const struct ieee80211_hdr_1addr *)fragment_data; - const struct ieee80211_security *secinfo = &bcm->ieee->sec; - u8 bitrate; - int ofdm_modulation; - u8 fallback_bitrate; - int fallback_ofdm_modulation; - u16 tmp; - u16 encrypt_frame; - - /* Now construct the TX header. */ - memset(txhdr, 0, sizeof(*txhdr)); - - //TODO: Some RTS/CTS stuff has to be done. - //TODO: Encryption stuff. - //TODO: others? - - bitrate = bcm->softmac->txrates.default_rate; - ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); - fallback_bitrate = bcm->softmac->txrates.default_fallback; - fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); - - /* Set Frame Control from 80211 header. */ - txhdr->frame_control = wireless_header->frame_ctl; - /* Copy address1 from 80211 header. */ - memcpy(txhdr->mac1, wireless_header->addr1, 6); - /* Set the fallback duration ID. */ - //FIXME: We use the original durid for now. - txhdr->fallback_dur_id = wireless_header->duration_id; - - /* Set the cookie (used as driver internal ID for the frame) */ - txhdr->cookie = cpu_to_le16(cookie); - - encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED; - if (encrypt_frame && !bcm->ieee->host_encrypt) { - const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header; - if (fragment_len <= sizeof(struct ieee80211_hdr_3addr)+4) { - dprintkl(KERN_ERR PFX "invalid packet with PROTECTED" - "flag set discarded"); - return; - } - memcpy(txhdr->wep_iv, hdr->payload, 4); - /* Hardware appends ICV. */ - fragment_len += 4; - } - - /* Generate the PLCP header and the fallback PLCP header. */ - bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp), - fragment_len, - bitrate, ofdm_modulation); - bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, fragment_len, - fallback_bitrate, fallback_ofdm_modulation); - - /* Set the CONTROL field */ - tmp = 0; - if (ofdm_modulation) - tmp |= BCM43xx_TXHDRCTL_OFDM; - if (bcm->short_preamble) //FIXME: could be the other way around, please test - tmp |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE; - tmp |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT) - & BCM43xx_TXHDRCTL_ANTENNADIV_MASK; - txhdr->control = cpu_to_le16(tmp); - - /* Set the FLAGS field */ - tmp = 0; - if (!is_multicast_ether_addr(wireless_header->addr1) && - !is_broadcast_ether_addr(wireless_header->addr1)) - tmp |= BCM43xx_TXHDRFLAG_EXPECTACK; - if (1 /* FIXME: PS poll?? */) - tmp |= 0x10; // FIXME: unknown meaning. - if (fallback_ofdm_modulation) - tmp |= BCM43xx_TXHDRFLAG_FALLBACKOFDM; - if (is_first_fragment) - tmp |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT; - txhdr->flags = cpu_to_le16(tmp); - - /* Set WSEC/RATE field */ - if (encrypt_frame && !bcm->ieee->host_encrypt) { - tmp = (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT) - & BCM43xx_TXHDR_WSEC_ALGO_MASK; - tmp |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT) - & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK; - txhdr->wsec_rate = cpu_to_le16(tmp); - } - -//bcm43xx_printk_bitdump((const unsigned char *)txhdr, sizeof(*txhdr), 1, "TX header"); -} - static void bcm43xx_macfilter_set(struct bcm43xx_private *bcm, u16 offset, @@ -3773,207 +3546,6 @@ err_pci_disable: goto out; } -static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, - u8 in_rssi, int ofdm, - int adjust_2053, int adjust_2050) -{ - s32 tmp; - - switch (bcm->current_core->radio->version) { - case 0x2050: - if (ofdm) { - tmp = in_rssi; - if (tmp > 127) - tmp -= 256; - tmp *= 73; - tmp /= 64; - if (adjust_2050) - tmp += 25; - else - tmp -= 3; - } else { - if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { - if (in_rssi > 63) - in_rssi = 63; - tmp = bcm->current_core->radio->nrssi_lt[in_rssi]; - tmp = 31 - tmp; - tmp *= -131; - tmp /= 128; - tmp -= 57; - } else { - tmp = in_rssi; - tmp = 31 - tmp; - tmp *= -149; - tmp /= 128; - tmp -= 68; - } - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G && - adjust_2050) - tmp += 25; - } - break; - case 0x2060: - if (in_rssi > 127) - tmp = in_rssi - 256; - else - tmp = in_rssi; - break; - default: - tmp = in_rssi; - tmp -= 11; - tmp *= 103; - tmp /= 64; - if (adjust_2053) - tmp -= 109; - else - tmp -= 83; - } - - return (s8)tmp; -} - -static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, - u8 in_rssi) -{ - s8 ret; - - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { - //TODO: Incomplete specs. - ret = 0; - } else - ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1); - - return ret; -} - -static inline -int bcm43xx_rx_packet(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct ieee80211_rx_stats *stats) -{ - int err; - - err = ieee80211_rx(bcm->ieee, skb, stats); - if (unlikely(err == 0)) - return -EINVAL; - return 0; -} - -int bcm43xx_rx(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct bcm43xx_rxhdr *rxhdr) -{ - struct bcm43xx_plcp_hdr4 *plcp; - struct ieee80211_rx_stats stats; - struct ieee80211_hdr_4addr *wlhdr; - u16 frame_ctl; - int is_packet_for_us = 0; - int err = -EINVAL; - const u16 rxflags1 = le16_to_cpu(rxhdr->flags1); - const u16 rxflags2 = le16_to_cpu(rxhdr->flags2); - const u16 rxflags3 = le16_to_cpu(rxhdr->flags3); - const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM); - - if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) { - plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2); - /* Skip two unknown bytes and the PLCP header. */ - skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6)); - } else { - plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data); - /* Skip the PLCP header. */ - skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6)); - } - /* The SKB contains the PAYLOAD (wireless header + data) - * at this point. The FCS at the end is stripped. - */ - - memset(&stats, 0, sizeof(stats)); - stats.mac_time = le16_to_cpu(rxhdr->mactime); - stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, - !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), - !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); - stats.signal = rxhdr->signal_quality; //FIXME -//TODO stats.noise = - stats.rate = bcm43xx_plcp_get_bitrate(plcp, is_ofdm); -//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); - stats.received_channel = bcm->current_core->radio->channel; -//TODO stats.control = - stats.mask = IEEE80211_STATMASK_SIGNAL | -//TODO IEEE80211_STATMASK_NOISE | - IEEE80211_STATMASK_RATE | - IEEE80211_STATMASK_RSSI; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) - stats.freq = IEEE80211_52GHZ_BAND; - else - stats.freq = IEEE80211_24GHZ_BAND; - stats.len = skb->len; - - bcm->stats.last_rx = jiffies; - if (bcm->ieee->iw_mode == IW_MODE_MONITOR) - return bcm43xx_rx_packet(bcm, skb, &stats); - - wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); - - switch (bcm->ieee->iw_mode) { - case IW_MODE_ADHOC: - if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || - memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || - is_broadcast_ether_addr(wlhdr->addr1) || - is_multicast_ether_addr(wlhdr->addr1) || - bcm->net_dev->flags & IFF_PROMISC) - is_packet_for_us = 1; - break; - case IW_MODE_INFRA: - default: - /* When receiving multicast or broadcast packets, filter out - the packets we send ourself; we shouldn't see those */ - if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || - memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || - (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) && - (is_broadcast_ether_addr(wlhdr->addr1) || - is_multicast_ether_addr(wlhdr->addr1) || - bcm->net_dev->flags & IFF_PROMISC))) - is_packet_for_us = 1; - break; - } - - frame_ctl = le16_to_cpu(wlhdr->frame_ctl); - if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) { - frame_ctl &= ~IEEE80211_FCTL_PROTECTED; - wlhdr->frame_ctl = cpu_to_le16(frame_ctl); - /* trim IV and ICV */ - /* FIXME: this must be done only for WEP encrypted packets */ - if (skb->len < 32) { - dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag " - "set and length < 32)\n"); - return -EINVAL; - } else { - memmove(skb->data + 4, skb->data, 24); - skb_pull(skb, 4); - skb_trim(skb, skb->len - 4); - stats.len -= 8; - } - wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); - } - - switch (WLAN_FC_GET_TYPE(frame_ctl)) { - case IEEE80211_FTYPE_MGMT: - ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats); - break; - case IEEE80211_FTYPE_DATA: - if (is_packet_for_us) - err = bcm43xx_rx_packet(bcm, skb, &stats); - break; - case IEEE80211_FTYPE_CTL: - break; - default: - assert(0); - return -EINVAL; - } - - return err; -} - /* Do the Hardware IO operations to send the txb */ static inline int bcm43xx_tx(struct bcm43xx_private *bcm, struct ieee80211_txb *txb) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index d460393ed34..086136c3d01 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -52,134 +52,12 @@ static inline void e_aton(char *str, char *dest) } #endif - -#define _bcm43xx_declare_plcp_hdr(size) \ - struct bcm43xx_plcp_hdr##size { \ - union { \ - __le32 data; \ - __u8 raw[size]; \ - } __attribute__((__packed__)); \ - } __attribute__((__packed__)) - -/* struct bcm43xx_plcp_hdr4 */ -_bcm43xx_declare_plcp_hdr(4); -/* struct bcm430c_plcp_hdr6 */ -_bcm43xx_declare_plcp_hdr(6); - -#undef _bcm43xx_declare_plcp_hdr - - #define P4D_BYT3S(magic, nr_bytes) u8 __p4dding##magic[nr_bytes] #define P4D_BYTES(line, nr_bytes) P4D_BYT3S(line, nr_bytes) /* Magic helper macro to pad structures. Ignore those above. It's magic. */ #define PAD_BYTES(nr_bytes) P4D_BYTES( __LINE__ , (nr_bytes)) -/* Device specific TX header. To be prepended to TX frames. */ -struct bcm43xx_txhdr { - union { - struct { - u16 flags; - u16 wsec_rate; - u16 frame_control; - u16 unknown_zeroed_0; - u16 control; - unsigned char wep_iv[10]; - unsigned char unknown_wsec_tkip_data[3]; //FIXME - PAD_BYTES(3); - unsigned char mac1[6]; - u16 unknown_zeroed_1; - struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp; - u16 rts_cts_dur_fallback; - struct bcm43xx_plcp_hdr4 fallback_plcp; - u16 fallback_dur_id; - PAD_BYTES(2); - u16 cookie; - u16 unknown_scb_stuff; //FIXME - struct bcm43xx_plcp_hdr6 rts_cts_plcp; - u16 rts_cts_frame_type; - u16 rts_cts_dur; - unsigned char rts_cts_mac1[6]; - unsigned char rts_cts_mac2[6]; - PAD_BYTES(2); - struct bcm43xx_plcp_hdr6 plcp; - } __attribute__((__packed__)); - - unsigned char raw[82]; - } __attribute__((__packed__)); -} __attribute__((__packed__)); - -struct sk_buff; - -void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, - struct bcm43xx_txhdr *txhdr, - const unsigned char *fragment_data, - const unsigned int fragment_len, - const int is_first_fragment, - const u16 cookie); - -/* RX header as received from the hardware. */ -struct bcm43xx_rxhdr { - /* Frame Length. Must be generated explicitely in PIO mode. */ - __le16 frame_length; - PAD_BYTES(2); - /* Flags field 1 */ - __le16 flags1; - u8 rssi; - u8 signal_quality; - PAD_BYTES(2); - /* Flags field 3 */ - __le16 flags3; - /* Flags field 2 */ - __le16 flags2; - /* Lower 16bits of the TSF at the time the frame started. */ - __le16 mactime; - PAD_BYTES(14); -} __attribute__((__packed__)); - -#define BCM43xx_RXHDR_FLAGS1_OFDM (1 << 0) -/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL??? (1 << 3) FIXME */ -#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE (1 << 7) -#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ (1 << 14) - -#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME (1 << 0) -#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME (1 << 2) -/*FIXME: WEP related flags */ - -#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ (1 << 10) - -/* Transmit Status as received from the hardware. */ -struct bcm43xx_hwxmitstatus { - PAD_BYTES(4); - __le16 cookie; - u8 flags; - u8 cnt1:4, - cnt2:4; - PAD_BYTES(2); - __le16 seq; - __le16 unknown; //FIXME -} __attribute__((__packed__)); - -/* Transmit Status in CPU byteorder. */ -struct bcm43xx_xmitstatus { - u16 cookie; - u8 flags; - u8 cnt1:4, - cnt2:4; - u16 seq; - u16 unknown; //FIXME -}; - -#define BCM43xx_TXSTAT_FLAG_ACK 0x01 -//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02 -//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04 -//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08 -//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10 -#define BCM43xx_TXSTAT_FLAG_IGNORE 0x20 -//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40 -//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80 - - /* Lightweight function to convert a frequency (in Mhz) to a channel number. */ static inline u8 bcm43xx_freq_to_channel_a(int freq) @@ -259,10 +137,6 @@ int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, void bcm43xx_tsf_read(struct bcm43xx_private *bcm, u64 *tsf); void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf); -int bcm43xx_rx(struct bcm43xx_private *bcm, - struct sk_buff *skb, - struct bcm43xx_rxhdr *rxhdr); - void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, int iw_mode); @@ -283,11 +157,6 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy); -int bcm43xx_pci_read_config_16(struct pci_dev *pdev, u16 offset, u16 *val); -int bcm43xx_pci_read_config_32(struct pci_dev *pdev, u16 offset, u32 *val); -int bcm43xx_pci_write_config_16(struct pci_dev *pdev, int offset, u16 val); -int bcm43xx_pci_write_config_32(struct pci_dev *pdev, int offset, u32 val); - void bcm43xx_mac_suspend(struct bcm43xx_private *bcm); void bcm43xx_mac_enable(struct bcm43xx_private *bcm); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 0bf4b3e26f9..7b45fa1314c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -26,6 +26,7 @@ #include "bcm43xx.h" #include "bcm43xx_pio.h" #include "bcm43xx_main.h" +#include "bcm43xx_xmit.h" #include diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c new file mode 100644 index 00000000000..5ee572e79f6 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c @@ -0,0 +1,579 @@ +/* + + Broadcom BCM43xx wireless driver + + Transmission (TX/RX) related functions. + + Copyright (c) 2005 Martin Langer , + Stefano Brivio + Michael Buesch + Danny van Dyk + Andreas Jaggi + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx_xmit.h" + +#include + + +/* Extract the bitrate out of a CCK PLCP header. */ +static u8 bcm43xx_plcp_get_bitrate_cck(struct bcm43xx_plcp_hdr4 *plcp) +{ + switch (plcp->raw[0]) { + case 0x0A: + return IEEE80211_CCK_RATE_1MB; + case 0x14: + return IEEE80211_CCK_RATE_2MB; + case 0x37: + return IEEE80211_CCK_RATE_5MB; + case 0x6E: + return IEEE80211_CCK_RATE_11MB; + } + assert(0); + return 0; +} + +/* Extract the bitrate out of an OFDM PLCP header. */ +static u8 bcm43xx_plcp_get_bitrate_ofdm(struct bcm43xx_plcp_hdr4 *plcp) +{ + switch (plcp->raw[0] & 0xF) { + case 0xB: + return IEEE80211_OFDM_RATE_6MB; + case 0xF: + return IEEE80211_OFDM_RATE_9MB; + case 0xA: + return IEEE80211_OFDM_RATE_12MB; + case 0xE: + return IEEE80211_OFDM_RATE_18MB; + case 0x9: + return IEEE80211_OFDM_RATE_24MB; + case 0xD: + return IEEE80211_OFDM_RATE_36MB; + case 0x8: + return IEEE80211_OFDM_RATE_48MB; + case 0xC: + return IEEE80211_OFDM_RATE_54MB; + } + assert(0); + return 0; +} + +u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate) +{ + switch (bitrate) { + case IEEE80211_CCK_RATE_1MB: + return 0x0A; + case IEEE80211_CCK_RATE_2MB: + return 0x14; + case IEEE80211_CCK_RATE_5MB: + return 0x37; + case IEEE80211_CCK_RATE_11MB: + return 0x6E; + } + assert(0); + return 0; +} + +u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate) +{ + switch (bitrate) { + case IEEE80211_OFDM_RATE_6MB: + return 0xB; + case IEEE80211_OFDM_RATE_9MB: + return 0xF; + case IEEE80211_OFDM_RATE_12MB: + return 0xA; + case IEEE80211_OFDM_RATE_18MB: + return 0xE; + case IEEE80211_OFDM_RATE_24MB: + return 0x9; + case IEEE80211_OFDM_RATE_36MB: + return 0xD; + case IEEE80211_OFDM_RATE_48MB: + return 0x8; + case IEEE80211_OFDM_RATE_54MB: + return 0xC; + } + assert(0); + return 0; +} + +static void bcm43xx_generate_plcp_hdr(struct bcm43xx_plcp_hdr4 *plcp, + const u16 octets, const u8 bitrate, + const int ofdm_modulation) +{ + __le32 *data = &(plcp->data); + __u8 *raw = plcp->raw; + + if (ofdm_modulation) { + *data = bcm43xx_plcp_get_ratecode_ofdm(bitrate); + assert(!(octets & 0xF000)); + *data |= (octets << 5); + *data = cpu_to_le32(*data); + } else { + u32 plen; + + plen = octets * 16 / bitrate; + if ((octets * 16 % bitrate) > 0) { + plen++; + if ((bitrate == IEEE80211_CCK_RATE_11MB) + && ((octets * 8 % 11) < 4)) { + raw[1] = 0x84; + } else + raw[1] = 0x04; + } else + raw[1] = 0x04; + *data |= cpu_to_le32(plen << 16); + raw[0] = bcm43xx_plcp_get_ratecode_cck(bitrate); + } +} + +static u8 bcm43xx_calc_fallback_rate(u8 bitrate) +{ + switch (bitrate) { + case IEEE80211_CCK_RATE_1MB: + return IEEE80211_CCK_RATE_1MB; + case IEEE80211_CCK_RATE_2MB: + return IEEE80211_CCK_RATE_1MB; + case IEEE80211_CCK_RATE_5MB: + return IEEE80211_CCK_RATE_2MB; + case IEEE80211_CCK_RATE_11MB: + return IEEE80211_CCK_RATE_5MB; + case IEEE80211_OFDM_RATE_6MB: + return IEEE80211_CCK_RATE_5MB; + case IEEE80211_OFDM_RATE_9MB: + return IEEE80211_OFDM_RATE_6MB; + case IEEE80211_OFDM_RATE_12MB: + return IEEE80211_OFDM_RATE_9MB; + case IEEE80211_OFDM_RATE_18MB: + return IEEE80211_OFDM_RATE_12MB; + case IEEE80211_OFDM_RATE_24MB: + return IEEE80211_OFDM_RATE_18MB; + case IEEE80211_OFDM_RATE_36MB: + return IEEE80211_OFDM_RATE_24MB; + case IEEE80211_OFDM_RATE_48MB: + return IEEE80211_OFDM_RATE_36MB; + case IEEE80211_OFDM_RATE_54MB: + return IEEE80211_OFDM_RATE_48MB; + } + assert(0); + return 0; +} + +static +__le16 bcm43xx_calc_duration_id(const struct ieee80211_hdr *wireless_header, + u8 bitrate) +{ + const u16 frame_ctl = le16_to_cpu(wireless_header->frame_ctl); + __le16 duration_id = wireless_header->duration_id; + + switch (WLAN_FC_GET_TYPE(frame_ctl)) { + case IEEE80211_FTYPE_DATA: + case IEEE80211_FTYPE_MGMT: + //TODO: Steal the code from ieee80211, once it is completed there. + break; + case IEEE80211_FTYPE_CTL: + /* Use the original duration/id. */ + break; + default: + assert(0); + } + + return duration_id; +} + +static inline +u16 ceiling_div(u16 dividend, u16 divisor) +{ + return ((dividend + divisor - 1) / divisor); +} + +static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy, + struct bcm43xx_txhdr *txhdr, + u16 *flags, + u8 bitrate, + const struct ieee80211_hdr_4addr *wlhdr) +{ + u16 fctl; + u16 dur; + u8 fallback_bitrate; + int ofdm_modulation; + int fallback_ofdm_modulation; + u8 *sa, *da; + u16 flen; + +//FIXME sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr); +//FIXME da = ieee80211_get_DA((struct ieee80211_hdr *)wlhdr); + fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate); + ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); + fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); + + flen = sizeof(u16) + sizeof(u16) + ETH_ALEN + ETH_ALEN + IEEE80211_FCS_LEN, + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_plcp), + flen, bitrate, + !ieee80211_is_cck_rate(bitrate)); + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->rts_cts_fallback_plcp), + flen, fallback_bitrate, + !ieee80211_is_cck_rate(fallback_bitrate)); + fctl = IEEE80211_FTYPE_CTL; + fctl |= IEEE80211_STYPE_RTS; + dur = le16_to_cpu(wlhdr->duration_id); +/*FIXME: should we test for dur==0 here and let it unmodified in this case? + * The following assert checks for this case... + */ +assert(dur); +/*FIXME: The duration calculation is not really correct. + * I am not 100% sure which bitrate to use. We use the RTS rate here, + * but this is likely to be wrong. + */ + if (phy->type == BCM43xx_PHYTYPE_A) { + /* Three times SIFS */ + dur += 16 * 3; + /* Add ACK duration. */ + dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10, + bitrate * 4); + /* Add CTS duration. */ + dur += ceiling_div((16 + 8 * (14 /*bytes*/) + 6) * 10, + bitrate * 4); + } else { + /* Three times SIFS */ + dur += 10 * 3; + /* Add ACK duration. */ + dur += ceiling_div(8 * (14 /*bytes*/) * 10, + bitrate); + /* Add CTS duration. */ + dur += ceiling_div(8 * (14 /*bytes*/) * 10, + bitrate); + } + + txhdr->rts_cts_frame_control = cpu_to_le16(fctl); + txhdr->rts_cts_dur = cpu_to_le16(dur); +//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3)); +//printk(BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da)); + memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME! + memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN); + + *flags |= BCM43xx_TXHDRFLAG_RTSCTS; + *flags |= BCM43xx_TXHDRFLAG_RTS; + if (ofdm_modulation) + *flags |= BCM43xx_TXHDRFLAG_RTSCTS_OFDM; + if (fallback_ofdm_modulation) + *flags |= BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM; +} + +void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + const unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie) +{ + const struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data; + const struct ieee80211_security *secinfo = &bcm->ieee->sec; + u8 bitrate; + u8 fallback_bitrate; + int ofdm_modulation; + int fallback_ofdm_modulation; + u16 plcp_fragment_len = fragment_len; + u16 flags = 0; + u16 control = 0; + u16 wsec_rate = 0; + u16 encrypt_frame; + + /* Now construct the TX header. */ + memset(txhdr, 0, sizeof(*txhdr)); + + bitrate = bcm->softmac->txrates.default_rate; + ofdm_modulation = !(ieee80211_is_cck_rate(bitrate)); + fallback_bitrate = bcm43xx_calc_fallback_rate(bitrate); + fallback_ofdm_modulation = !(ieee80211_is_cck_rate(fallback_bitrate)); + + /* Set Frame Control from 80211 header. */ + txhdr->frame_control = wireless_header->frame_ctl; + /* Copy address1 from 80211 header. */ + memcpy(txhdr->mac1, wireless_header->addr1, 6); + /* Set the fallback duration ID. */ + txhdr->fallback_dur_id = bcm43xx_calc_duration_id((const struct ieee80211_hdr *)wireless_header, + fallback_bitrate); + /* Set the cookie (used as driver internal ID for the frame) */ + txhdr->cookie = cpu_to_le16(cookie); + + /* Hardware appends FCS. */ + plcp_fragment_len += IEEE80211_FCS_LEN; + + /* Hardware encryption. */ + encrypt_frame = le16_to_cpup(&wireless_header->frame_ctl) & IEEE80211_FCTL_PROTECTED; + if (encrypt_frame && !bcm->ieee->host_encrypt) { + const struct ieee80211_hdr_3addr *hdr = (struct ieee80211_hdr_3addr *)wireless_header; + memcpy(txhdr->wep_iv, hdr->payload, 4); + /* Hardware appends ICV. */ + plcp_fragment_len += 4; + + wsec_rate |= (bcm->key[secinfo->active_key].algorithm << BCM43xx_TXHDR_WSEC_ALGO_SHIFT) + & BCM43xx_TXHDR_WSEC_ALGO_MASK; + wsec_rate |= (secinfo->active_key << BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT) + & BCM43xx_TXHDR_WSEC_KEYINDEX_MASK; + } + + /* Generate the PLCP header and the fallback PLCP header. */ + bcm43xx_generate_plcp_hdr((struct bcm43xx_plcp_hdr4 *)(&txhdr->plcp), + plcp_fragment_len, + bitrate, ofdm_modulation); + bcm43xx_generate_plcp_hdr(&txhdr->fallback_plcp, plcp_fragment_len, + fallback_bitrate, fallback_ofdm_modulation); + + /* Set the CONTROL field */ + if (ofdm_modulation) + control |= BCM43xx_TXHDRCTL_OFDM; + if (bcm->short_preamble) //FIXME: could be the other way around, please test + control |= BCM43xx_TXHDRCTL_SHORT_PREAMBLE; + control |= (phy->antenna_diversity << BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT) + & BCM43xx_TXHDRCTL_ANTENNADIV_MASK; + + /* Set the FLAGS field */ + if (!is_multicast_ether_addr(wireless_header->addr1) && + !is_broadcast_ether_addr(wireless_header->addr1)) + flags |= BCM43xx_TXHDRFLAG_EXPECTACK; + if (1 /* FIXME: PS poll?? */) + flags |= 0x10; // FIXME: unknown meaning. + if (fallback_ofdm_modulation) + flags |= BCM43xx_TXHDRFLAG_FALLBACKOFDM; + if (is_first_fragment) + flags |= BCM43xx_TXHDRFLAG_FIRSTFRAGMENT; + + /* Set WSEC/RATE field */ + wsec_rate |= (txhdr->plcp.raw[0] << BCM43xx_TXHDR_RATE_SHIFT) + & BCM43xx_TXHDR_RATE_MASK; + + /* Generate the RTS/CTS packet, if required. */ + /* FIXME: We should first try with CTS-to-self, + * if we are on 80211g. If we get too many + * failures (hidden nodes), we should switch back to RTS/CTS. + */ + if (0/*FIXME txctl->use_rts_cts*/) { + bcm43xx_generate_rts(phy, txhdr, &flags, + 0/*FIXME txctl->rts_cts_rate*/, + wireless_header); + } + + txhdr->flags = cpu_to_le16(flags); + txhdr->control = cpu_to_le16(control); + txhdr->wsec_rate = cpu_to_le16(wsec_rate); +} + +static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, + u8 in_rssi, int ofdm, + int adjust_2053, int adjust_2050) +{ + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + s32 tmp; + + switch (radio->version) { + case 0x2050: + if (ofdm) { + tmp = in_rssi; + if (tmp > 127) + tmp -= 256; + tmp *= 73; + tmp /= 64; + if (adjust_2050) + tmp += 25; + else + tmp -= 3; + } else { + if (bcm->sprom.boardflags & BCM43xx_BFL_RSSI) { + if (in_rssi > 63) + in_rssi = 63; + tmp = radio->nrssi_lt[in_rssi]; + tmp = 31 - tmp; + tmp *= -131; + tmp /= 128; + tmp -= 57; + } else { + tmp = in_rssi; + tmp = 31 - tmp; + tmp *= -149; + tmp /= 128; + tmp -= 68; + } + if (phy->type == BCM43xx_PHYTYPE_G && + adjust_2050) + tmp += 25; + } + break; + case 0x2060: + if (in_rssi > 127) + tmp = in_rssi - 256; + else + tmp = in_rssi; + break; + default: + tmp = in_rssi; + tmp -= 11; + tmp *= 103; + tmp /= 64; + if (adjust_2053) + tmp -= 109; + else + tmp -= 83; + } + + return (s8)tmp; +} + +static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, + u8 in_rssi) +{ + struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + s8 ret; + + if (phy->type == BCM43xx_PHYTYPE_A) { + //TODO: Incomplete specs. + ret = 0; + } else + ret = bcm43xx_rssi_postprocess(bcm, in_rssi, 0, 1, 1); + + return ret; +} + +int bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr) +{ + struct bcm43xx_plcp_hdr4 *plcp; + struct ieee80211_rx_stats stats; + struct ieee80211_hdr_4addr *wlhdr; + u16 frame_ctl; + int is_packet_for_us = 0; + int err = -EINVAL; + const u16 rxflags1 = le16_to_cpu(rxhdr->flags1); + const u16 rxflags2 = le16_to_cpu(rxhdr->flags2); + const u16 rxflags3 = le16_to_cpu(rxhdr->flags3); + const int is_ofdm = !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_OFDM); + + if (rxflags2 & BCM43xx_RXHDR_FLAGS2_TYPE2FRAME) { + plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data + 2); + /* Skip two unknown bytes and the PLCP header. */ + skb_pull(skb, 2 + sizeof(struct bcm43xx_plcp_hdr6)); + } else { + plcp = (struct bcm43xx_plcp_hdr4 *)(skb->data); + /* Skip the PLCP header. */ + skb_pull(skb, sizeof(struct bcm43xx_plcp_hdr6)); + } + /* The SKB contains the PAYLOAD (wireless header + data) + * at this point. The FCS at the end is stripped. + */ + + memset(&stats, 0, sizeof(stats)); + stats.mac_time = le16_to_cpu(rxhdr->mactime); + stats.rssi = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm, + !!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ), + !!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ)); + stats.signal = rxhdr->signal_quality; //FIXME +//TODO stats.noise = + if (is_ofdm) + stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp); + else + stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); +//printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); + stats.received_channel = bcm->current_core->radio->channel; +//TODO stats.control = + stats.mask = IEEE80211_STATMASK_SIGNAL | +//TODO IEEE80211_STATMASK_NOISE | + IEEE80211_STATMASK_RATE | + IEEE80211_STATMASK_RSSI; + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + stats.freq = IEEE80211_52GHZ_BAND; + else + stats.freq = IEEE80211_24GHZ_BAND; + stats.len = skb->len; + + bcm->stats.last_rx = jiffies; + if (bcm->ieee->iw_mode == IW_MODE_MONITOR) { + err = ieee80211_rx(bcm->ieee, skb, &stats); + return (err == 0) ? -EINVAL : 0; + } + + wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); + + switch (bcm->ieee->iw_mode) { + case IW_MODE_ADHOC: + if (memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || + memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || + is_broadcast_ether_addr(wlhdr->addr1) || + is_multicast_ether_addr(wlhdr->addr1) || + bcm->net_dev->flags & IFF_PROMISC) + is_packet_for_us = 1; + break; + case IW_MODE_INFRA: + default: + /* When receiving multicast or broadcast packets, filter out + the packets we send ourself; we shouldn't see those */ + if (memcmp(wlhdr->addr3, bcm->ieee->bssid, ETH_ALEN) == 0 || + memcmp(wlhdr->addr1, bcm->net_dev->dev_addr, ETH_ALEN) == 0 || + (memcmp(wlhdr->addr3, bcm->net_dev->dev_addr, ETH_ALEN) && + (is_broadcast_ether_addr(wlhdr->addr1) || + is_multicast_ether_addr(wlhdr->addr1) || + bcm->net_dev->flags & IFF_PROMISC))) + is_packet_for_us = 1; + break; + } + + frame_ctl = le16_to_cpu(wlhdr->frame_ctl); + if ((frame_ctl & IEEE80211_FCTL_PROTECTED) && !bcm->ieee->host_decrypt) { + frame_ctl &= ~IEEE80211_FCTL_PROTECTED; + wlhdr->frame_ctl = cpu_to_le16(frame_ctl); + /* trim IV and ICV */ + /* FIXME: this must be done only for WEP encrypted packets */ + if (skb->len < 32) { + dprintkl(KERN_ERR PFX "RX packet dropped (PROTECTED flag " + "set and length < 32)\n"); + return -EINVAL; + } else { + memmove(skb->data + 4, skb->data, 24); + skb_pull(skb, 4); + skb_trim(skb, skb->len - 4); + stats.len -= 8; + } + wlhdr = (struct ieee80211_hdr_4addr *)(skb->data); + } + + switch (WLAN_FC_GET_TYPE(frame_ctl)) { + case IEEE80211_FTYPE_MGMT: + ieee80211_rx_mgt(bcm->ieee, wlhdr, &stats); + break; + case IEEE80211_FTYPE_DATA: + if (is_packet_for_us) { + err = ieee80211_rx(bcm->ieee, skb, &stats); + err = (err == 0) ? -EINVAL : 0; + } + break; + case IEEE80211_FTYPE_CTL: + break; + default: + assert(0); + return -EINVAL; + } + + return err; +} + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h new file mode 100644 index 00000000000..2aed19e35c7 --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.h @@ -0,0 +1,156 @@ +#ifndef BCM43xx_XMIT_H_ +#define BCM43xx_XMIT_H_ + +#include "bcm43xx_main.h" + + +#define _bcm43xx_declare_plcp_hdr(size) \ + struct bcm43xx_plcp_hdr##size { \ + union { \ + __le32 data; \ + __u8 raw[size]; \ + } __attribute__((__packed__)); \ + } __attribute__((__packed__)) + +/* struct bcm43xx_plcp_hdr4 */ +_bcm43xx_declare_plcp_hdr(4); +/* struct bcm43xx_plcp_hdr6 */ +_bcm43xx_declare_plcp_hdr(6); + +#undef _bcm43xx_declare_plcp_hdr + +/* Device specific TX header. To be prepended to TX frames. */ +struct bcm43xx_txhdr { + union { + struct { + __le16 flags; + __le16 wsec_rate; + __le16 frame_control; + u16 unknown_zeroed_0; + __le16 control; + u8 wep_iv[10]; + u8 unknown_wsec_tkip_data[3]; //FIXME + PAD_BYTES(3); + u8 mac1[6]; + u16 unknown_zeroed_1; + struct bcm43xx_plcp_hdr4 rts_cts_fallback_plcp; + __le16 rts_cts_dur_fallback; + struct bcm43xx_plcp_hdr4 fallback_plcp; + __le16 fallback_dur_id; + PAD_BYTES(2); + __le16 cookie; + __le16 unknown_scb_stuff; //FIXME + struct bcm43xx_plcp_hdr6 rts_cts_plcp; + __le16 rts_cts_frame_control; + __le16 rts_cts_dur; + u8 rts_cts_mac1[6]; + u8 rts_cts_mac2[6]; + PAD_BYTES(2); + struct bcm43xx_plcp_hdr6 plcp; + } __attribute__((__packed__)); + u8 raw[82]; + } __attribute__((__packed__)); +} __attribute__((__packed__)); + +/* Values/Masks for the device TX header */ +#define BCM43xx_TXHDRFLAG_EXPECTACK 0x0001 +#define BCM43xx_TXHDRFLAG_RTSCTS 0x0002 +#define BCM43xx_TXHDRFLAG_RTS 0x0004 +#define BCM43xx_TXHDRFLAG_FIRSTFRAGMENT 0x0008 +#define BCM43xx_TXHDRFLAG_DESTPSMODE 0x0020 +#define BCM43xx_TXHDRFLAG_RTSCTS_OFDM 0x0080 +#define BCM43xx_TXHDRFLAG_FALLBACKOFDM 0x0100 +#define BCM43xx_TXHDRFLAG_RTSCTSFALLBACK_OFDM 0x0200 +#define BCM43xx_TXHDRFLAG_CTS 0x0400 +#define BCM43xx_TXHDRFLAG_FRAMEBURST 0x0800 + +#define BCM43xx_TXHDRCTL_OFDM 0x0001 +#define BCM43xx_TXHDRCTL_SHORT_PREAMBLE 0x0010 +#define BCM43xx_TXHDRCTL_ANTENNADIV_MASK 0x0030 +#define BCM43xx_TXHDRCTL_ANTENNADIV_SHIFT 8 + +#define BCM43xx_TXHDR_RATE_MASK 0x0F00 +#define BCM43xx_TXHDR_RATE_SHIFT 8 +#define BCM43xx_TXHDR_RTSRATE_MASK 0xF000 +#define BCM43xx_TXHDR_RTSRATE_SHIFT 12 +#define BCM43xx_TXHDR_WSEC_KEYINDEX_MASK 0x00F0 +#define BCM43xx_TXHDR_WSEC_KEYINDEX_SHIFT 4 +#define BCM43xx_TXHDR_WSEC_ALGO_MASK 0x0003 +#define BCM43xx_TXHDR_WSEC_ALGO_SHIFT 0 + +void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, + struct bcm43xx_txhdr *txhdr, + const unsigned char *fragment_data, + const unsigned int fragment_len, + const int is_first_fragment, + const u16 cookie); + +/* RX header as received from the hardware. */ +struct bcm43xx_rxhdr { + /* Frame Length. Must be generated explicitely in PIO mode. */ + __le16 frame_length; + PAD_BYTES(2); + /* Flags field 1 */ + __le16 flags1; + u8 rssi; + u8 signal_quality; + PAD_BYTES(2); + /* Flags field 3 */ + __le16 flags3; + /* Flags field 2 */ + __le16 flags2; + /* Lower 16bits of the TSF at the time the frame started. */ + __le16 mactime; + PAD_BYTES(14); +} __attribute__((__packed__)); + +#define BCM43xx_RXHDR_FLAGS1_OFDM (1 << 0) +/*#define BCM43xx_RXHDR_FLAGS1_SIGNAL??? (1 << 3) FIXME */ +#define BCM43xx_RXHDR_FLAGS1_SHORTPREAMBLE (1 << 7) +#define BCM43xx_RXHDR_FLAGS1_2053RSSIADJ (1 << 14) + +#define BCM43xx_RXHDR_FLAGS2_INVALIDFRAME (1 << 0) +#define BCM43xx_RXHDR_FLAGS2_TYPE2FRAME (1 << 2) +/*FIXME: WEP related flags */ + +#define BCM43xx_RXHDR_FLAGS3_2050RSSIADJ (1 << 10) + +/* Transmit Status as received from the hardware. */ +struct bcm43xx_hwxmitstatus { + PAD_BYTES(4); + __le16 cookie; + u8 flags; + u8 cnt1:4, + cnt2:4; + PAD_BYTES(2); + __le16 seq; + __le16 unknown; //FIXME +} __attribute__((__packed__)); + +/* Transmit Status in CPU byteorder. */ +struct bcm43xx_xmitstatus { + u16 cookie; + u8 flags; + u8 cnt1:4, + cnt2:4; + u16 seq; + u16 unknown; //FIXME +}; + +#define BCM43xx_TXSTAT_FLAG_ACK 0x01 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x02 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x04 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x08 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x10 +#define BCM43xx_TXSTAT_FLAG_IGNORE 0x20 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x40 +//TODO #define BCM43xx_TXSTAT_FLAG_??? 0x80 + +u8 bcm43xx_plcp_get_ratecode_cck(const u8 bitrate); +u8 bcm43xx_plcp_get_ratecode_ofdm(const u8 bitrate); + +int bcm43xx_rx(struct bcm43xx_private *bcm, + struct sk_buff *skb, + struct bcm43xx_rxhdr *rxhdr); + +#endif /* BCM43xx_XMIT_H_ */ -- cgit v1.2.3 From 367f899ac3b52cf4611cd291ec2bfbf774b15bc7 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 28 Feb 2006 15:32:19 +0100 Subject: [PATCH] bcm43xx: Add sysfs attributes for device specific tunables. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/Makefile | 2 +- drivers/net/wireless/bcm43xx/bcm43xx.h | 3 + drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 + drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 323 +++++++++++++++++++++++++++ drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h | 25 +++ 5 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c create mode 100644 drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/Makefile b/drivers/net/wireless/bcm43xx/Makefile index 2962b5f9e3e..bb5220c629d 100644 --- a/drivers/net/wireless/bcm43xx/Makefile +++ b/drivers/net/wireless/bcm43xx/Makefile @@ -8,5 +8,5 @@ bcm43xx-objs := bcm43xx_main.o bcm43xx_ilt.o \ bcm43xx_radio.o bcm43xx_phy.o \ bcm43xx_power.o bcm43xx_wx.o \ bcm43xx_leds.o bcm43xx_ethtool.o \ - bcm43xx_xmit.o \ + bcm43xx_xmit.o bcm43xx_sysfs.o \ $(bcm43xx-obj-y) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 21c75cae14b..fd9754b5295 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -15,6 +15,7 @@ #include "bcm43xx_debugfs.h" #include "bcm43xx_leds.h" +#include "bcm43xx_sysfs.h" #define PFX KBUILD_MODNAME ": " @@ -606,6 +607,8 @@ struct bcm43xx_key { }; struct bcm43xx_private { + struct bcm43xx_sysfs sysfs; + struct ieee80211_device *ieee; struct ieee80211softmac_device *softmac; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index f1ac9940f14..1fe2fa9856e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3160,6 +3160,8 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) int i, err; unsigned long flags; + bcm43xx_sysfs_unregister(bcm); + bcm43xx_periodic_tasks_delete(bcm); spin_lock_irqsave(&bcm->lock, flags); @@ -3270,6 +3272,8 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) spin_unlock_irqrestore(&bcm->lock, flags); bcm43xx_periodic_tasks_setup(bcm); + bcm43xx_sysfs_register(bcm); + //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though... assert(err == 0); out: diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c new file mode 100644 index 00000000000..2d31737372f --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c @@ -0,0 +1,323 @@ +/* + + Broadcom BCM43xx wireless driver + + SYSFS support routines + + Copyright (c) 2006 Michael Buesch + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, + Boston, MA 02110-1301, USA. + +*/ + +#include "bcm43xx_sysfs.h" +#include "bcm43xx.h" +#include "bcm43xx_main.h" +#include "bcm43xx_radio.h" + +#include + + +#define GENERIC_FILESIZE 64 + + +static int get_integer(const char *buf, size_t count) +{ + char tmp[10 + 1] = { 0 }; + int ret = -EINVAL; + + if (count == 0) + goto out; + count = min(count, (size_t)10); + memcpy(tmp, buf, count); + ret = simple_strtol(tmp, NULL, 10); +out: + return ret; +} + +static int get_boolean(const char *buf, size_t count) +{ + if (count != 0) { + if (buf[0] == '1') + return 1; + if (buf[0] == '0') + return 0; + if (count >= 4 && memcmp(buf, "true", 4) == 0) + return 1; + if (count >= 5 && memcmp(buf, "false", 5) == 0) + return 0; + if (count >= 3 && memcmp(buf, "yes", 3) == 0) + return 1; + if (count >= 2 && memcmp(buf, "no", 2) == 0) + return 0; + if (count >= 2 && memcmp(buf, "on", 2) == 0) + return 1; + if (count >= 3 && memcmp(buf, "off", 3) == 0) + return 0; + } + return -EINVAL; +} + +static ssize_t bcm43xx_attr_sprom_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); + u16 *sprom; + unsigned long flags; + int i, err; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + assert(BCM43xx_SPROM_SIZE * sizeof(u16) <= PAGE_SIZE); + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), + GFP_KERNEL); + if (!sprom) + return -ENOMEM; + spin_lock_irqsave(&bcm->lock, flags); + assert(bcm->initialized); + err = bcm43xx_sprom_read(bcm, sprom); + if (!err) { + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + buf[i * 2] = sprom[i] & 0x00FF; + buf[i * 2 + 1] = (sprom[i] & 0xFF00) >> 8; + } + } + spin_unlock_irqrestore(&bcm->lock, flags); + kfree(sprom); + + return err ? err : BCM43xx_SPROM_SIZE * sizeof(u16); +} + +static ssize_t bcm43xx_attr_sprom_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_sprom); + u16 *sprom; + unsigned long flags; + int i, err; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (count != BCM43xx_SPROM_SIZE * sizeof(u16)) + return -EINVAL; + sprom = kmalloc(BCM43xx_SPROM_SIZE * sizeof(*sprom), + GFP_KERNEL); + if (!sprom) + return -ENOMEM; + for (i = 0; i < BCM43xx_SPROM_SIZE; i++) { + sprom[i] = buf[i * 2] & 0xFF; + sprom[i] |= ((u16)(buf[i * 2 + 1] & 0xFF)) << 8; + } + spin_lock_irqsave(&bcm->lock, flags); + assert(bcm->initialized); + err = bcm43xx_sprom_write(bcm, sprom); + spin_unlock_irqrestore(&bcm->lock, flags); + kfree(sprom); + + return err ? err : count; + +} + +static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); + unsigned long flags; + int err; + ssize_t count = 0; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + spin_lock_irqsave(&bcm->lock, flags); + assert(bcm->initialized); + + switch (bcm->current_core->radio->interfmode) { + case BCM43xx_RADIO_INTERFMODE_NONE: + count = snprintf(buf, PAGE_SIZE, "0 (No Interference Mitigation)\n"); + break; + case BCM43xx_RADIO_INTERFMODE_NONWLAN: + count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference Mitigation)\n"); + break; + case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: + count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference Mitigation)\n"); + break; + default: + assert(0); + } + err = 0; + + spin_unlock_irqrestore(&bcm->lock, flags); + return err ? err : count; + +} + +static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_interfmode); + unsigned long flags; + int err; + int mode; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + mode = get_integer(buf, count); + switch (mode) { + case 0: + mode = BCM43xx_RADIO_INTERFMODE_NONE; + break; + case 1: + mode = BCM43xx_RADIO_INTERFMODE_NONWLAN; + break; + case 2: + mode = BCM43xx_RADIO_INTERFMODE_MANUALWLAN; + break; + case 3: + mode = BCM43xx_RADIO_INTERFMODE_AUTOWLAN; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&bcm->lock, flags); + assert(bcm->initialized); + + err = bcm43xx_radio_set_interference_mitigation(bcm, mode); + if (err) { + printk(KERN_ERR PFX "Interference Mitigation not " + "supported by device\n"); + } + + spin_unlock_irqrestore(&bcm->lock, flags); + + return err ? err : count; +} + +static ssize_t bcm43xx_attr_preamble_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); + unsigned long flags; + int err; + ssize_t count; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + spin_lock_irqsave(&bcm->lock, flags); + assert(bcm->initialized); + + if (bcm->short_preamble) + count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n"); + else + count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); + + err = 0; + spin_unlock_irqrestore(&bcm->lock, flags); + + return err ? err : count; +} + +static ssize_t bcm43xx_attr_preamble_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct bcm43xx_private *bcm = devattr_to_bcm(attr, attr_preamble); + unsigned long flags; + int err; + int value; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + value = get_boolean(buf, count); + if (value < 0) + return value; + spin_lock_irqsave(&bcm->lock, flags); + assert(bcm->initialized); + + bcm->short_preamble = !!value; + + err = 0; + spin_unlock_irqrestore(&bcm->lock, flags); + + return err ? err : count; +} + +int bcm43xx_sysfs_register(struct bcm43xx_private *bcm) +{ + struct device *dev = &bcm->pci_dev->dev; + struct bcm43xx_sysfs *sysfs = &bcm->sysfs; + int err; + + assert(bcm->initialized); + + sysfs->attr_sprom.attr.name = "sprom"; + sysfs->attr_sprom.attr.owner = THIS_MODULE; + sysfs->attr_sprom.attr.mode = 0600; + sysfs->attr_sprom.show = bcm43xx_attr_sprom_show; + sysfs->attr_sprom.store = bcm43xx_attr_sprom_store; + err = device_create_file(dev, &sysfs->attr_sprom); + if (err) + goto out; + + sysfs->attr_interfmode.attr.name = "interference"; + sysfs->attr_interfmode.attr.owner = THIS_MODULE; + sysfs->attr_interfmode.attr.mode = 0600; + sysfs->attr_interfmode.show = bcm43xx_attr_interfmode_show; + sysfs->attr_interfmode.store = bcm43xx_attr_interfmode_store; + err = device_create_file(dev, &sysfs->attr_interfmode); + if (err) + goto err_remove_sprom; + + sysfs->attr_preamble.attr.name = "shortpreamble"; + sysfs->attr_preamble.attr.owner = THIS_MODULE; + sysfs->attr_preamble.attr.mode = 0600; + sysfs->attr_preamble.show = bcm43xx_attr_preamble_show; + sysfs->attr_preamble.store = bcm43xx_attr_preamble_store; + err = device_create_file(dev, &sysfs->attr_preamble); + if (err) + goto err_remove_interfmode; + +out: + return err; +err_remove_interfmode: + device_remove_file(dev, &sysfs->attr_interfmode); +err_remove_sprom: + device_remove_file(dev, &sysfs->attr_sprom); + goto out; +} + +void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm) +{ + struct device *dev = &bcm->pci_dev->dev; + struct bcm43xx_sysfs *sysfs = &bcm->sysfs; + + device_remove_file(dev, &sysfs->attr_preamble); + device_remove_file(dev, &sysfs->attr_interfmode); + device_remove_file(dev, &sysfs->attr_sprom); +} + +/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h new file mode 100644 index 00000000000..57f14514e3e --- /dev/null +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.h @@ -0,0 +1,25 @@ +#ifndef BCM43xx_SYSFS_H_ +#define BCM43xx_SYSFS_H_ + +#include + + +struct bcm43xx_sysfs { + struct device_attribute attr_sprom; + struct device_attribute attr_interfmode; + struct device_attribute attr_preamble; +}; + +#define devattr_to_bcm(attr, attr_name) ({ \ + struct bcm43xx_sysfs *__s; struct bcm43xx_private *__p; \ + __s = container_of((attr), struct bcm43xx_sysfs, attr_name); \ + __p = container_of(__s, struct bcm43xx_private, sysfs); \ + __p; \ + }) + +struct bcm43xx_private; + +int bcm43xx_sysfs_register(struct bcm43xx_private *bcm); +void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm); + +#endif /* BCM43xx_SYSFS_H_ */ -- cgit v1.2.3 From 512a80916b8d04529c0915534c63529144f74e10 Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 7 Mar 2006 01:37:51 +0100 Subject: [PATCH] bcm43xx: fix DMA TX skb freeing in case of fragmented packets. It seems to me that the today's wireless-2.6 git contains bcm43xx which does not free txb's correctly, if I understand it right. Consider a situation where a txb with two skb's is sent down. The dma_tx_fragment will save the pointer to meta->txb of the first fragment. If fragments are freed in order, ieee80211_txb_free frees both skb's when the first fragment is processed. This may result in reuse of the second skb's memory. This danger is rather remote, but it seems to me that the patch below not only fixes the problem, but also makes the code simpler, which is good, right? Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 44 ++++++------------------------ drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 4 --- 2 files changed, 8 insertions(+), 40 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index e20fbaf29e0..0cd29284795 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -170,19 +170,6 @@ void sync_descbuffer_for_device(struct bcm43xx_dmaring *ring, addr, len, DMA_FROM_DEVICE); } -static inline -void mark_skb_mustfree(struct sk_buff *skb, - char mustfree) -{ - skb->cb[0] = mustfree; -} - -static inline -int skb_mustfree(struct sk_buff *skb) -{ - return (skb->cb[0] != 0); -} - /* Unmap and free a descriptor buffer. */ static inline void free_descriptor_buffer(struct bcm43xx_dmaring *ring, @@ -191,17 +178,11 @@ void free_descriptor_buffer(struct bcm43xx_dmaring *ring, int irq_context) { assert(meta->skb); - if (skb_mustfree(meta->skb)) { - if (irq_context) - dev_kfree_skb_irq(meta->skb); - else - dev_kfree_skb(meta->skb); - } + if (irq_context) + dev_kfree_skb_irq(meta->skb); + else + dev_kfree_skb(meta->skb); meta->skb = NULL; - if (meta->txb) { - ieee80211_txb_free(meta->txb); - meta->txb = NULL; - } } static int alloc_ringmemory(struct bcm43xx_dmaring *ring) @@ -334,7 +315,6 @@ static int setup_rx_descbuffer(struct bcm43xx_dmaring *ring, meta->skb = skb; meta->dmaaddr = dmaaddr; skb->dev = ring->bcm->net_dev; - mark_skb_mustfree(skb, 1); desc_addr = (u32)(dmaaddr + ring->memoffset); desc_ctl = (BCM43xx_DMADTOR_BYTECNT_MASK & (u32)(ring->rx_buffersize - ring->frameoffset)); @@ -457,7 +437,6 @@ static void free_all_descbuffers(struct bcm43xx_dmaring *ring) if (!meta->skb) { assert(ring->tx); - assert(!meta->txb); continue; } if (ring->tx) { @@ -726,7 +705,6 @@ static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, static int dma_tx_fragment(struct bcm43xx_dmaring *ring, struct sk_buff *skb, - struct ieee80211_txb *txb, u8 cur_frag) { int slot; @@ -741,11 +719,6 @@ static int dma_tx_fragment(struct bcm43xx_dmaring *ring, desc = ring->vbase + slot; meta = ring->meta + slot; - if (cur_frag == 0) { - /* Save the txb pointer for freeing in xmitstatus IRQ */ - meta->txb = txb; - } - /* Add a device specific TX header. */ assert(skb_headroom(skb) >= sizeof(struct bcm43xx_txhdr)); /* Reserve enough headroom for the device tx header. */ @@ -810,13 +783,12 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, for (i = 0; i < txb->nr_frags; i++) { skb = txb->fragments[i]; - /* We do not free the skb, as it is freed as - * part of the txb freeing. - */ - mark_skb_mustfree(skb, 0); - dma_tx_fragment(ring, skb, txb, i); + /* Take skb from ieee80211_txb_free */ + txb->fragments[i] = NULL; + dma_tx_fragment(ring, skb, i); //TODO: handle failure of dma_tx_fragment } + ieee80211_txb_free(txb); return 0; } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h index 88ad34dff2f..cab8e2ba4c7 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -119,10 +119,6 @@ struct bcm43xx_dmadesc_meta { struct sk_buff *skb; /* DMA base bus-address of the descriptor buffer. */ dma_addr_t dmaaddr; - /* Pointer to our txb (can be NULL). - * This should be freed in completion IRQ. - */ - struct ieee80211_txb *txb; }; struct bcm43xx_dmaring { -- cgit v1.2.3 From 4d5a9e0eeb7ec928c6bd55db410f09ed3779bc2a Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 11 Mar 2006 13:15:02 +0100 Subject: [PATCH] bcm43xx: Set both, the DMAmask and the coherent DMAmask. This has a potential to fix the >1G bug. But I can not test that, yet. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 1fe2fa9856e..6da0beb0a93 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3717,6 +3717,8 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, struct net_device *net_dev, struct pci_dev *pci_dev) { + int err; + bcm->ieee = netdev_priv(net_dev); bcm->softmac = ieee80211_priv(net_dev); bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; @@ -3735,8 +3737,7 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; bcm->pci_dev = pci_dev; bcm->net_dev = net_dev; - if (modparam_bad_frames_preempt) - bcm->bad_frames_preempt = 1; + bcm->bad_frames_preempt = modparam_bad_frames_preempt; spin_lock_init(&bcm->lock); tasklet_init(&bcm->isr_tasklet, (void (*)(unsigned long))bcm43xx_interrupt_tasklet, @@ -3745,7 +3746,9 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, if (modparam_pio) { bcm->__using_pio = 1; } else { - if (pci_set_dma_mask(pci_dev, DMA_30BIT_MASK)) { + err = pci_set_dma_mask(pci_dev, DMA_30BIT_MASK); + err |= pci_set_consistent_dma_mask(pci_dev, DMA_30BIT_MASK); + if (err) { #ifdef CONFIG_BCM43XX_PIO printk(KERN_WARNING PFX "DMA not supported. Falling back to PIO.\n"); bcm->__using_pio = 1; -- cgit v1.2.3 From efccb647f486ff8174b4db0ab8145df8dd42ce6d Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 11 Mar 2006 13:39:14 +0100 Subject: [PATCH] bcm43xx: Abstract the locking mechanism. This is the starting point to make the driver out-of-order-MMIO-stores safe. There are more mmiowb() needed. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 20 ++++- drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 26 +++--- drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 4 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 75 +++++++++-------- drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 4 +- drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 25 +++--- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 112 ++++++++++++------------- 7 files changed, 142 insertions(+), 124 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index fd9754b5295..5f8c63fab83 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -619,7 +619,9 @@ struct bcm43xx_private { void __iomem *mmio_addr; unsigned int mmio_len; - spinlock_t lock; + /* Do not use the lock directly. Use the bcm43xx_lock* helper + * functions, to be MMIO-safe. */ + spinlock_t _lock; /* Driver status flags. */ u32 initialized:1, /* init_board() succeed */ @@ -721,6 +723,22 @@ struct bcm43xx_private { #endif }; +/* bcm43xx_(un)lock() protect struct bcm43xx_private. + * Note that _NO_ MMIO writes are allowed. If you want to + * write to the device through MMIO in the critical section, use + * the *_mmio lock functions. + * MMIO read-access is allowed, though. + */ +#define bcm43xx_lock(bcm, flags) spin_lock_irqsave(&(bcm)->_lock, flags) +#define bcm43xx_unlock(bcm, flags) spin_unlock_irqrestore(&(bcm)->_lock, flags) +/* bcm43xx_(un)lock_mmio() protect struct bcm43xx_private and MMIO. + * MMIO write-access to the device is allowed. + * All MMIO writes are flushed on unlock, so it is guaranteed to not + * interfere with other threads writing MMIO registers. + */ +#define bcm43xx_lock_mmio(bcm, flags) bcm43xx_lock(bcm, flags) +#define bcm43xx_unlock_mmio(bcm, flags) do { mmiowb(); bcm43xx_unlock(bcm, flags); } while (0) + static inline struct bcm43xx_private * bcm43xx_priv(struct net_device *dev) { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index 0bae0be4be2..bcfcebe2826 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -77,7 +77,7 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, down(&big_buffer_sem); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (!bcm->initialized) { fappend("Board not initialized.\n"); goto out; @@ -124,7 +124,7 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, fappend("\n"); out: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); up(&big_buffer_sem); return res; @@ -162,7 +162,7 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, unsigned long flags; down(&big_buffer_sem); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (!bcm->initialized) { fappend("Board not initialized.\n"); goto out; @@ -172,7 +172,7 @@ static ssize_t spromdump_read_file(struct file *file, char __user *userbuf, fappend("boardflags: 0x%04x\n", bcm->sprom.boardflags); out: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); up(&big_buffer_sem); return res; @@ -191,7 +191,7 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf, u64 tsf; down(&big_buffer_sem); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (!bcm->initialized) { fappend("Board not initialized.\n"); goto out; @@ -202,7 +202,7 @@ static ssize_t tsf_read_file(struct file *file, char __user *userbuf, (unsigned int)(tsf & 0xFFFFFFFFULL)); out: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); up(&big_buffer_sem); return res; @@ -224,7 +224,7 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, res = -EFAULT; goto out_up; } - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (!bcm->initialized) { printk(KERN_INFO PFX "debugfs: Board not initialized.\n"); res = -EFAULT; @@ -239,7 +239,7 @@ static ssize_t tsf_write_file(struct file *file, const char __user *user_buf, res = buf_size; out_unlock: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); out_up: up(&big_buffer_sem); return res; @@ -260,7 +260,7 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf, int i, cnt, j = 0; down(&big_buffer_sem); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); fappend("Last %d logged xmitstatus blobs (Latest first):\n\n", BCM43xx_NR_LOGGED_XMITSTATUS); @@ -296,14 +296,14 @@ static ssize_t txstat_read_file(struct file *file, char __user *userbuf, i = BCM43xx_NR_LOGGED_XMITSTATUS - 1; } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); if (*ppos == pos) { /* Done. Drop the copied data. */ e->xmitstatus_printing = 0; } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); up(&big_buffer_sem); return res; } @@ -419,7 +419,7 @@ void bcm43xx_debugfs_log_txstat(struct bcm43xx_private *bcm, struct bcm43xx_dfsentry *e; struct bcm43xx_xmitstatus *savedstatus; - /* This is protected by bcm->lock */ + /* This is protected by bcm->_lock */ e = bcm->dfsentry; assert(e); savedstatus = e->xmitstatus_buffer + e->xmitstatus_ptr; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index 8f550c1a92e..949555da5aa 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -51,12 +51,12 @@ static void bcm43xx_led_blink(unsigned long d) struct bcm43xx_private *bcm = led->bcm; unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (led->blink_interval) { bcm43xx_led_changestate(led); mod_timer(&led->blink_timer, jiffies + led->blink_interval); } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); } static void bcm43xx_led_blink_start(struct bcm43xx_led *led, diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 6da0beb0a93..b7192559833 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -482,14 +482,14 @@ static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *old u32 old; unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) { - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return -EBUSY; } old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); tasklet_disable(&bcm->isr_tasklet); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); if (oldstate) *oldstate = old; @@ -746,6 +746,7 @@ int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom) else if (i % 2) printk("."); bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]); + mmiowb(); mdelay(20); } spromctl &= ~0x10; /* SPROM WRITE enable. */ @@ -1676,7 +1677,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) # define bcmirq_handled(irq) do { /* nothing */ } while (0) #endif /* CONFIG_BCM43XX_DEBUG*/ - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); reason = bcm->irq_reason; dma_reason[0] = bcm->dma_reason[0]; dma_reason[1] = bcm->dma_reason[1]; @@ -1776,7 +1777,7 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) if (!modparam_noleds) bcm43xx_leds_update(bcm, activity); bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); } #undef bcmirq_print_reasons @@ -1830,25 +1831,24 @@ static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, /* Interrupt handler top-half */ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs) { + irqreturn_t ret = IRQ_HANDLED; struct bcm43xx_private *bcm = dev_id; u32 reason, mask; if (!bcm) return IRQ_NONE; - spin_lock(&bcm->lock); + spin_lock(&bcm->_lock); reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); if (reason == 0xffffffff) { /* irq not for us (shared irq) */ - spin_unlock(&bcm->lock); - return IRQ_NONE; + ret = IRQ_NONE; + goto out; } mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); - if (!(reason & mask)) { - spin_unlock(&bcm->lock); - return IRQ_HANDLED; - } + if (!(reason & mask)) + goto out; bcm43xx_interrupt_ack(bcm, reason, mask); @@ -1866,9 +1866,11 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re tasklet_schedule(&bcm->isr_tasklet); } - spin_unlock(&bcm->lock); +out: + mmiowb(); + spin_unlock(&bcm->_lock); - return IRQ_HANDLED; + return ret; } static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) @@ -3112,7 +3114,7 @@ static void bcm43xx_periodic_task_handler(unsigned long d) unsigned long flags; unsigned int state; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); assert(bcm->initialized); state = bcm->periodic_state; @@ -3127,7 +3129,7 @@ static void bcm43xx_periodic_task_handler(unsigned long d) mod_timer(&bcm->periodic_tasks, jiffies + (HZ * 15)); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); } static void bcm43xx_periodic_tasks_delete(struct bcm43xx_private *bcm) @@ -3164,10 +3166,10 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) bcm43xx_periodic_tasks_delete(bcm); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); bcm->initialized = 0; bcm->shutting_down = 1; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE)) @@ -3182,9 +3184,9 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) bcm43xx_pctl_set_crystal(bcm, 0); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); bcm->shutting_down = 0; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); } static int bcm43xx_init_board(struct bcm43xx_private *bcm) @@ -3196,10 +3198,10 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) might_sleep(); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); bcm->initialized = 0; bcm->shutting_down = 0; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); err = bcm43xx_pctl_set_crystal(bcm, 1); if (err) @@ -3267,9 +3269,9 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) } /* Initialization of the board is done. Flag it as such. */ - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); bcm->initialized = 1; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); bcm43xx_periodic_tasks_setup(bcm); bcm43xx_sysfs_register(bcm); @@ -3570,11 +3572,11 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); bcm43xx_mac_suspend(bcm); bcm43xx_radio_selectchannel(bcm, channel, 0); bcm43xx_mac_enable(bcm); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); } /* set_security() callback in struct ieee80211_device */ @@ -3587,9 +3589,9 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, int keyidx; dprintk(KERN_INFO PFX "set security called\n"); - - spin_lock_irqsave(&bcm->lock, flags); - + + bcm43xx_lock_mmio(bcm, flags); + for (keyidx = 0; keyidxflags & (1<encode_alg[keyidx] = sec->encode_alg[keyidx]; @@ -3651,7 +3653,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev, } else bcm43xx_clear_keys(bcm); } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); } /* hard_start_xmit() callback in struct ieee80211_device */ @@ -3663,10 +3665,10 @@ static int bcm43xx_ieee80211_hard_start_xmit(struct ieee80211_txb *txb, int err = -ENODEV; unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (likely(bcm->initialized)) err = bcm43xx_tx(bcm, txb); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return err; } @@ -3679,8 +3681,11 @@ static struct net_device_stats * bcm43xx_net_get_stats(struct net_device *net_de static void bcm43xx_net_tx_timeout(struct net_device *net_dev) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + unsigned long flags; + bcm43xx_lock_mmio(bcm, flags); bcm43xx_controller_restart(bcm, "TX timeout"); + bcm43xx_unlock_mmio(bcm, flags); } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -3738,7 +3743,7 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, bcm->pci_dev = pci_dev; bcm->net_dev = net_dev; bcm->bad_frames_preempt = modparam_bad_frames_preempt; - spin_lock_init(&bcm->lock); + spin_lock_init(&bcm->_lock); tasklet_init(&bcm->isr_tasklet, (void (*)(unsigned long))bcm43xx_interrupt_tasklet, (unsigned long)bcm); @@ -3921,11 +3926,11 @@ static int bcm43xx_suspend(struct pci_dev *pdev, pm_message_t state) dprintk(KERN_INFO PFX "Suspending...\n"); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); bcm->was_initialized = bcm->initialized; if (bcm->initialized) try_to_shutdown = 1; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); netif_device_detach(net_dev); if (try_to_shutdown) { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 7b45fa1314c..26dc6047d45 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -258,7 +258,7 @@ static void tx_tasklet(unsigned long d) struct bcm43xx_pio_txpacket *packet, *tmp_packet; int err; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); list_for_each_entry_safe(packet, tmp_packet, &queue->txqueue, list) { assert(packet->xmitted_frags < packet->txb->nr_frags); if (packet->xmitted_frags == 0) { @@ -288,7 +288,7 @@ static void tx_tasklet(unsigned long d) next_packet: continue; } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); } static void setup_txqueues(struct bcm43xx_pioqueue *queue) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c index 2d31737372f..713ec601c34 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c @@ -88,7 +88,7 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev, GFP_KERNEL); if (!sprom) return -ENOMEM; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); assert(bcm->initialized); err = bcm43xx_sprom_read(bcm, sprom); if (!err) { @@ -97,7 +97,7 @@ static ssize_t bcm43xx_attr_sprom_show(struct device *dev, buf[i * 2 + 1] = (sprom[i] & 0xFF00) >> 8; } } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); kfree(sprom); return err ? err : BCM43xx_SPROM_SIZE * sizeof(u16); @@ -125,10 +125,10 @@ static ssize_t bcm43xx_attr_sprom_store(struct device *dev, sprom[i] = buf[i * 2] & 0xFF; sprom[i] |= ((u16)(buf[i * 2 + 1] & 0xFF)) << 8; } - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); assert(bcm->initialized); err = bcm43xx_sprom_write(bcm, sprom); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); kfree(sprom); return err ? err : count; @@ -147,7 +147,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); assert(bcm->initialized); switch (bcm->current_core->radio->interfmode) { @@ -165,7 +165,8 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, } err = 0; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); + return err ? err : count; } @@ -200,7 +201,7 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, return -EINVAL; } - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); assert(bcm->initialized); err = bcm43xx_radio_set_interference_mitigation(bcm, mode); @@ -209,7 +210,7 @@ static ssize_t bcm43xx_attr_interfmode_store(struct device *dev, "supported by device\n"); } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return err ? err : count; } @@ -226,7 +227,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev, if (!capable(CAP_NET_ADMIN)) return -EPERM; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); assert(bcm->initialized); if (bcm->short_preamble) @@ -235,7 +236,7 @@ static ssize_t bcm43xx_attr_preamble_show(struct device *dev, count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n"); err = 0; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return err ? err : count; } @@ -255,13 +256,13 @@ static ssize_t bcm43xx_attr_preamble_store(struct device *dev, value = get_boolean(buf, count); if (value < 0) return value; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); assert(bcm->initialized); bcm->short_preamble = !!value; err = 0; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return err ? err : count; } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index aa2d9930c43..208193851e8 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -61,7 +61,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, char suffix[7] = { 0 }; int have_a = 0, have_b = 0, have_g = 0; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); nr_80211 = bcm43xx_num_80211_cores(bcm); for (i = 0; i < nr_80211; i++) { phy = bcm->phy + i; @@ -78,7 +78,7 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, assert(0); } } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); i = 0; if (have_a) { @@ -113,7 +113,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, int freq; int err = -EINVAL; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if ((data->freq.m >= 0) && (data->freq.m <= 1000)) { channel = data->freq.m; freq = bcm43xx_channel_to_freq(bcm, channel); @@ -133,7 +133,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, err = 0; } out_unlock: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return err; } @@ -148,7 +148,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, int err = -ENODEV; u16 channel; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); channel = bcm->current_core->radio->channel; if (channel == 0xFF) { assert(!bcm->initialized); @@ -163,7 +163,7 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, err = 0; out_unlock: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return err; } @@ -181,10 +181,10 @@ static int bcm43xx_wx_set_mode(struct net_device *net_dev, if (mode == IW_MODE_AUTO) mode = BCM43xx_INITIAL_IWMODE; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (bcm->ieee->iw_mode != mode) bcm43xx_set_iwmode(bcm, mode); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return 0; } @@ -197,9 +197,9 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); data->mode = bcm->ieee->iw_mode; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -269,7 +269,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); range->num_bitrates = 0; i = 0; @@ -315,7 +315,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, } range->num_frequency = j; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -329,11 +329,11 @@ static int bcm43xx_wx_set_nick(struct net_device *net_dev, unsigned long flags; size_t len; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); len = min((size_t)data->data.length, (size_t)IW_ESSID_MAX_SIZE); memcpy(bcm->nick, extra, len); bcm->nick[len] = '\0'; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -347,12 +347,12 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev, unsigned long flags; size_t len; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); len = strlen(bcm->nick) + 1; memcpy(extra, bcm->nick, len); data->data.length = (__u16)len; data->data.flags = 1; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -366,7 +366,7 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, unsigned long flags; int err = -EINVAL; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); if (data->rts.disabled) { bcm->rts_threshold = BCM43xx_MAX_RTS_THRESHOLD; err = 0; @@ -377,7 +377,7 @@ static int bcm43xx_wx_set_rts(struct net_device *net_dev, err = 0; } } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return err; } @@ -390,11 +390,11 @@ static int bcm43xx_wx_get_rts(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); data->rts.value = bcm->rts_threshold; data->rts.fixed = 0; data->rts.disabled = (bcm->rts_threshold == BCM43xx_MAX_RTS_THRESHOLD); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -408,7 +408,7 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, unsigned long flags; int err = -EINVAL; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); if (data->frag.disabled) { bcm->ieee->fts = MAX_FRAG_THRESHOLD; err = 0; @@ -419,7 +419,7 @@ static int bcm43xx_wx_set_frag(struct net_device *net_dev, err = 0; } } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return err; } @@ -432,11 +432,11 @@ static int bcm43xx_wx_get_frag(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); data->frag.value = bcm->ieee->fts; data->frag.fixed = 0; data->frag.disabled = (bcm->ieee->fts == MAX_FRAG_THRESHOLD); - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -458,7 +458,7 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, return -EOPNOTSUPP; } - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (!bcm->initialized) goto out_unlock; radio = bcm->current_core->radio; @@ -482,7 +482,7 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, err = 0; out_unlock: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return err; } @@ -497,7 +497,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, unsigned long flags; int err = -ENODEV; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); if (!bcm->initialized) goto out_unlock; radio = bcm->current_core->radio; @@ -509,7 +509,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, err = 0; out_unlock: - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return err; } @@ -632,7 +632,7 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, return -EINVAL; } - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); if (bcm->initialized) { err = bcm43xx_radio_set_interference_mitigation(bcm, mode); if (err) { @@ -647,7 +647,7 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, } else bcm->current_core->radio->interfmode = mode; } - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock_mmio(bcm, flags); return err; } @@ -661,9 +661,9 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, unsigned long flags; int mode; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); mode = bcm->current_core->radio->interfmode; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); switch (mode) { case BCM43xx_RADIO_INTERFMODE_NONE: @@ -693,9 +693,9 @@ static int bcm43xx_wx_set_shortpreamble(struct net_device *net_dev, int on; on = *((int *)extra); - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); bcm->short_preamble = !!on; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); return 0; } @@ -709,9 +709,9 @@ static int bcm43xx_wx_get_shortpreamble(struct net_device *net_dev, unsigned long flags; int on; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock(bcm, flags); on = bcm->short_preamble; - spin_unlock_irqrestore(&bcm->lock, flags); + bcm43xx_unlock(bcm, flags); if (on) strncpy(extra, "1 (Short Preamble enabled)", MAX_WX_STRING); @@ -732,13 +732,13 @@ static int bcm43xx_wx_set_swencryption(struct net_device *net_dev, int on; on = *((int *)extra); - spin_lock_irqsave(&bcm->lock, flags); + + bcm43xx_lock(bcm, flags); bcm->ieee->host_encrypt = !!on; bcm->ieee->host_decrypt = !!on; bcm->ieee->host_build_iv = !on; - - spin_unlock_irqrestore(&bcm->lock, flags); - + bcm43xx_unlock(bcm, flags); + return 0; } @@ -750,17 +750,17 @@ static int bcm43xx_wx_get_swencryption(struct net_device *net_dev, struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; int on; - - spin_lock_irqsave(&bcm->lock, flags); + + bcm43xx_lock(bcm, flags); on = bcm->ieee->host_encrypt; - spin_unlock_irqrestore(&bcm->lock, flags); - + bcm43xx_unlock(bcm, flags); + if (on) strncpy(extra, "1 (SW encryption enabled) ", MAX_WX_STRING); else strncpy(extra, "0 (SW encryption disabled) ", MAX_WX_STRING); data->data.length = strlen(extra + 1); - + return 0; } @@ -816,17 +816,13 @@ static int bcm43xx_wx_sprom_read(struct net_device *net_dev, if (!sprom) goto out; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); err = -ENODEV; - if (!bcm->initialized) { - spin_unlock_irqrestore(&bcm->lock, flags); - goto out_kfree; - } - err = bcm43xx_sprom_read(bcm, sprom); - spin_unlock_irqrestore(&bcm->lock, flags); + if (bcm->initialized) + err = bcm43xx_sprom_read(bcm, sprom); + bcm43xx_unlock_mmio(bcm, flags); if (!err) data->data.length = sprom2hex(sprom, extra); -out_kfree: kfree(sprom); out: return err; @@ -865,13 +861,11 @@ static int bcm43xx_wx_sprom_write(struct net_device *net_dev, if (err) goto out_kfree; - spin_lock_irqsave(&bcm->lock, flags); + bcm43xx_lock_mmio(bcm, flags); err = -ENODEV; - if (!bcm->initialized) - goto out_unlock; - err = bcm43xx_sprom_write(bcm, sprom); -out_unlock: - spin_unlock_irqrestore(&bcm->lock, flags); + if (bcm->initialized) + err = bcm43xx_sprom_write(bcm, sprom); + bcm43xx_unlock_mmio(bcm, flags); out_kfree: kfree(sprom); out: -- cgit v1.2.3 From 7ce942d0ff5df145831631f4df391c7207e676bb Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 11 Mar 2006 13:43:06 +0100 Subject: [PATCH] bcm43xx: Remove the mmio access printing facility overhead. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 101 ++-------------------------- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 35 ---------- 2 files changed, 6 insertions(+), 130 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 5f8c63fab83..29c95b07122 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -718,8 +718,6 @@ struct bcm43xx_private { /* Debugging stuff follows. */ #ifdef CONFIG_BCM43XX_DEBUG struct bcm43xx_dfsentry *dfsentry; - atomic_t mmio_print_cnt; - atomic_t pcicfg_print_cnt; #endif }; @@ -805,141 +803,54 @@ struct bcm43xx_lopair * bcm43xx_get_lopair(struct bcm43xx_phyinfo *phy, } -/* MMIO read/write functions. Debug and non-debug variants. */ -#ifdef CONFIG_BCM43XX_DEBUG - static inline u16 bcm43xx_read16(struct bcm43xx_private *bcm, u16 offset) { - u16 value; - - value = ioread16(bcm->mmio_addr + core_offset(bcm) + offset); - if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { - printk(KERN_INFO PFX "ioread16 offset: 0x%04x, value: 0x%04x\n", - offset, value); - } - - return value; + return ioread16(bcm->mmio_addr + core_offset(bcm) + offset); } static inline void bcm43xx_write16(struct bcm43xx_private *bcm, u16 offset, u16 value) { iowrite16(value, bcm->mmio_addr + core_offset(bcm) + offset); - if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { - printk(KERN_INFO PFX "iowrite16 offset: 0x%04x, value: 0x%04x\n", - offset, value); - } } static inline u32 bcm43xx_read32(struct bcm43xx_private *bcm, u16 offset) { - u32 value; - - value = ioread32(bcm->mmio_addr + core_offset(bcm) + offset); - if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { - printk(KERN_INFO PFX "ioread32 offset: 0x%04x, value: 0x%08x\n", - offset, value); - } - - return value; + return ioread32(bcm->mmio_addr + core_offset(bcm) + offset); } static inline void bcm43xx_write32(struct bcm43xx_private *bcm, u16 offset, u32 value) { iowrite32(value, bcm->mmio_addr + core_offset(bcm) + offset); - if (unlikely(atomic_read(&bcm->mmio_print_cnt) > 0)) { - printk(KERN_INFO PFX "iowrite32 offset: 0x%04x, value: 0x%08x\n", - offset, value); - } } static inline int bcm43xx_pci_read_config16(struct bcm43xx_private *bcm, int offset, u16 *value) { - int err; - - err = pci_read_config_word(bcm->pci_dev, offset, value); - if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { - printk(KERN_INFO PFX "pciread16 offset: 0x%08x, value: 0x%04x, err: %d\n", - offset, *value, err); - } - - return err; + return pci_read_config_word(bcm->pci_dev, offset, value); } static inline int bcm43xx_pci_read_config32(struct bcm43xx_private *bcm, int offset, u32 *value) { - int err; - - err = pci_read_config_dword(bcm->pci_dev, offset, value); - if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { - printk(KERN_INFO PFX "pciread32 offset: 0x%08x, value: 0x%08x, err: %d\n", - offset, *value, err); - } - - return err; + return pci_read_config_dword(bcm->pci_dev, offset, value); } static inline int bcm43xx_pci_write_config16(struct bcm43xx_private *bcm, int offset, u16 value) { - int err; - - err = pci_write_config_word(bcm->pci_dev, offset, value); - if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { - printk(KERN_INFO PFX "pciwrite16 offset: 0x%08x, value: 0x%04x, err: %d\n", - offset, value, err); - } - - return err; + return pci_write_config_word(bcm->pci_dev, offset, value); } static inline int bcm43xx_pci_write_config32(struct bcm43xx_private *bcm, int offset, u32 value) { - int err; - - err = pci_write_config_dword(bcm->pci_dev, offset, value); - if (unlikely(atomic_read(&bcm->pcicfg_print_cnt) > 0)) { - printk(KERN_INFO PFX "pciwrite32 offset: 0x%08x, value: 0x%08x, err: %d\n", - offset, value, err); - } - - return err; + return pci_write_config_dword(bcm->pci_dev, offset, value); } -#define bcm43xx_mmioprint_initial(bcm, value) atomic_set(&(bcm)->mmio_print_cnt, (value)) -#define bcm43xx_mmioprint_enable(bcm) atomic_inc(&(bcm)->mmio_print_cnt) -#define bcm43xx_mmioprint_disable(bcm) atomic_dec(&(bcm)->mmio_print_cnt) -#define bcm43xx_pciprint_initial(bcm, value) atomic_set(&(bcm)->pcicfg_print_cnt, (value)) -#define bcm43xx_pciprint_enable(bcm) atomic_inc(&(bcm)->pcicfg_print_cnt) -#define bcm43xx_pciprint_disable(bcm) atomic_dec(&(bcm)->pcicfg_print_cnt) - -#else /* CONFIG_BCM43XX_DEBUG*/ - -#define bcm43xx_read16(bcm, offset) ioread16((bcm)->mmio_addr + core_offset(bcm) + (offset)) -#define bcm43xx_write16(bcm, offset, value) iowrite16((value), (bcm)->mmio_addr + core_offset(bcm) + (offset)) -#define bcm43xx_read32(bcm, offset) ioread32((bcm)->mmio_addr + core_offset(bcm) + (offset)) -#define bcm43xx_write32(bcm, offset, value) iowrite32((value), (bcm)->mmio_addr + core_offset(bcm) + (offset)) -#define bcm43xx_pci_read_config16(bcm, o, v) pci_read_config_word((bcm)->pci_dev, (o), (v)) -#define bcm43xx_pci_read_config32(bcm, o, v) pci_read_config_dword((bcm)->pci_dev, (o), (v)) -#define bcm43xx_pci_write_config16(bcm, o, v) pci_write_config_word((bcm)->pci_dev, (o), (v)) -#define bcm43xx_pci_write_config32(bcm, o, v) pci_write_config_dword((bcm)->pci_dev, (o), (v)) - -#define bcm43xx_mmioprint_initial(x, y) do { /* nothing */ } while (0) -#define bcm43xx_mmioprint_enable(x) do { /* nothing */ } while (0) -#define bcm43xx_mmioprint_disable(x) do { /* nothing */ } while (0) -#define bcm43xx_pciprint_initial(bcm, value) do { /* nothing */ } while (0) -#define bcm43xx_pciprint_enable(bcm) do { /* nothing */ } while (0) -#define bcm43xx_pciprint_disable(bcm) do { /* nothing */ } while (0) - -#endif /* CONFIG_BCM43XX_DEBUG*/ - - /** Limit a value between two limits */ #ifdef limit_value # undef limit_value diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index b7192559833..f3cef345c8f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2018,12 +2018,6 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) const u32 *data; unsigned int i, len; -#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT - bcm43xx_mmioprint_enable(bcm); -#else - bcm43xx_mmioprint_disable(bcm); -#endif - /* Upload Microcode. */ data = (u32 *)(bcm->ucode->data); len = bcm->ucode->size / sizeof(u32); @@ -2045,12 +2039,6 @@ static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm) be32_to_cpu(data[i])); udelay(10); } - -#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT - bcm43xx_mmioprint_disable(bcm); -#else - bcm43xx_mmioprint_enable(bcm); -#endif } static int bcm43xx_write_initvals(struct bcm43xx_private *bcm, @@ -2090,12 +2078,6 @@ static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) { int err; -#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT - bcm43xx_mmioprint_enable(bcm); -#else - bcm43xx_mmioprint_disable(bcm); -#endif - err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, bcm->initvals0->size / sizeof(struct bcm43xx_initval)); if (err) @@ -2106,13 +2088,7 @@ static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm) if (err) goto out; } - out: -#ifdef DEBUG_ENABLE_UCODE_MMIO_PRINT - bcm43xx_mmioprint_disable(bcm); -#else - bcm43xx_mmioprint_enable(bcm); -#endif return err; } @@ -3728,17 +3704,6 @@ static int bcm43xx_init_private(struct bcm43xx_private *bcm, bcm->softmac = ieee80211_priv(net_dev); bcm->softmac->set_channel = bcm43xx_ieee80211_set_chan; -#ifdef DEBUG_ENABLE_MMIO_PRINT - bcm43xx_mmioprint_initial(bcm, 1); -#else - bcm43xx_mmioprint_initial(bcm, 0); -#endif -#ifdef DEBUG_ENABLE_PCILOG - bcm43xx_pciprint_initial(bcm, 1); -#else - bcm43xx_pciprint_initial(bcm, 0); -#endif - bcm->irq_savedstate = BCM43xx_IRQ_INITIAL; bcm->pci_dev = pci_dev; bcm->net_dev = net_dev; -- cgit v1.2.3 From 73733847beead47dc31b1f8e1532e5eea9f8ddd3 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 12 Mar 2006 19:44:29 +0100 Subject: [PATCH] bcm43xx: fix some stuff, add a few missing mmiowb(), remove dead code. This may workaround the XMIT ERRORs some people are getting. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 23 +--- drivers/net/wireless/bcm43xx/bcm43xx_ilt.c | 42 +----- drivers/net/wireless/bcm43xx/bcm43xx_ilt.h | 6 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 76 +++++++---- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 187 ++++++++++++++------------- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 20 +-- 6 files changed, 167 insertions(+), 187 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h index cab8e2ba4c7..c07e34689be 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -9,27 +9,10 @@ /* DMA-Interrupt reasons. */ -/*TODO: add the missing ones. */ -#define BCM43xx_DMAIRQ_ERR0 (1 << 10) -#define BCM43xx_DMAIRQ_ERR1 (1 << 11) -#define BCM43xx_DMAIRQ_ERR2 (1 << 12) -#define BCM43xx_DMAIRQ_ERR3 (1 << 13) -#define BCM43xx_DMAIRQ_ERR4 (1 << 14) -#define BCM43xx_DMAIRQ_ERR5 (1 << 15) +#define BCM43xx_DMAIRQ_FATALMASK ((1 << 10) | (1 << 11) | (1 << 12) \ + | (1 << 14) | (1 << 15)) +#define BCM43xx_DMAIRQ_NONFATALMASK (1 << 13) #define BCM43xx_DMAIRQ_RX_DONE (1 << 16) -/* helpers */ -#define BCM43xx_DMAIRQ_ANYERR (BCM43xx_DMAIRQ_ERR0 | \ - BCM43xx_DMAIRQ_ERR1 | \ - BCM43xx_DMAIRQ_ERR2 | \ - BCM43xx_DMAIRQ_ERR3 | \ - BCM43xx_DMAIRQ_ERR4 | \ - BCM43xx_DMAIRQ_ERR5) -#define BCM43xx_DMAIRQ_FATALERR (BCM43xx_DMAIRQ_ERR0 | \ - BCM43xx_DMAIRQ_ERR1 | \ - BCM43xx_DMAIRQ_ERR2 | \ - BCM43xx_DMAIRQ_ERR4 | \ - BCM43xx_DMAIRQ_ERR5) -#define BCM43xx_DMAIRQ_NONFATALERR BCM43xx_DMAIRQ_ERR3 /* DMA controller register offsets. (relative to BCM43xx_DMA#_BASE) */ #define BCM43xx_DMA_TX_CONTROL 0x00 diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c index 22587e0e1a0..865ed5c3361 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c @@ -312,20 +312,22 @@ const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE] = { /**** Helper functions to access the device Internal Lookup Tables ****/ -void bcm43xx_ilt_write16(struct bcm43xx_private *bcm, u16 offset, u16 val) +void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val) { - if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); + mmiowb(); bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val); } else { bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); + mmiowb(); bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, val); } } -u16 bcm43xx_ilt_read16(struct bcm43xx_private *bcm, u16 offset) +u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset) { - if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { + if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1); } else { @@ -333,35 +335,3 @@ u16 bcm43xx_ilt_read16(struct bcm43xx_private *bcm, u16 offset) return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1); } } - -void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val) -{ - if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA2, (u16)(val >> 16)); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, (u16)(val & 0x0000FFFF)); - } else { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA2, (u16)(val >> 16)); - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_DATA1, (u16)(val & 0x0000FFFF)); - } -} - -u32 bcm43xx_ilt_read32(struct bcm43xx_private *bcm, u16 offset) -{ - u32 ret; - - if ( bcm->current_core->phy->type == BCM43xx_PHYTYPE_A ) { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); - ret = bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA2); - ret <<= 16; - ret |= bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1); - } else { - bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_G_CTRL, offset); - ret = bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA2); - ret <<= 16; - ret |= bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_G_DATA1); - } - - return ret; -} diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h index d92527fd83e..464521abf73 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.h @@ -26,9 +26,7 @@ extern const u16 bcm43xx_ilt_sigmasqr1[BCM43xx_ILT_SIGMASQR_SIZE]; extern const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE]; -void bcm43xx_ilt_write16(struct bcm43xx_private *bcm, u16 offset, u16 val); -u16 bcm43xx_ilt_read16(struct bcm43xx_private *bcm, u16 offset); -void bcm43xx_ilt_write32(struct bcm43xx_private *bcm, u16 offset, u32 val); -u32 bcm43xx_ilt_read32(struct bcm43xx_private *bcm, u16 offset); +void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val); +u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset); #endif /* BCM43xx_ILT_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index f3cef345c8f..a563258cad3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -155,6 +155,7 @@ static void bcm43xx_ram_write(struct bcm43xx_private *bcm, u16 offset, u32 val) val = swab32(val); bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_CONTROL, offset); + mmiowb(); bcm43xx_write32(bcm, BCM43xx_MMIO_RAM_DATA, val); } @@ -225,9 +226,12 @@ void bcm43xx_shm_write32(struct bcm43xx_private *bcm, if (offset & 0x0003) { /* Unaligned access */ bcm43xx_shm_control_word(bcm, routing, offset >> 2); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, (value >> 16) & 0xffff); + mmiowb(); bcm43xx_shm_control_word(bcm, routing, (offset >> 2) + 1); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value & 0xffff); return; @@ -235,6 +239,7 @@ void bcm43xx_shm_write32(struct bcm43xx_private *bcm, offset >>= 2; } bcm43xx_shm_control_word(bcm, routing, offset); + mmiowb(); bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, value); } @@ -246,6 +251,7 @@ void bcm43xx_shm_write16(struct bcm43xx_private *bcm, if (offset & 0x0003) { /* Unaligned access */ bcm43xx_shm_control_word(bcm, routing, offset >> 2); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA_UNALIGNED, value); return; @@ -253,6 +259,7 @@ void bcm43xx_shm_write16(struct bcm43xx_private *bcm, offset >>= 2; } bcm43xx_shm_control_word(bcm, routing, offset); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_SHM_DATA, value); } @@ -311,6 +318,7 @@ void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); status |= BCM43xx_SBF_TIME_UPDATE; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + mmiowb(); /* Be careful with the in-progress timer. * First zero out the low register, so we have a full @@ -320,9 +328,10 @@ void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) u32 lo = (tsf & 0x00000000FFFFFFFFULL); u32 hi = (tsf & 0xFFFFFFFF00000000ULL) >> 32; - barrier(); bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, 0); + mmiowb(); bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_HIGH, hi); + mmiowb(); bcm43xx_write32(bcm, BCM43xx_MMIO_REV3PLUS_TSF_LOW, lo); } else { u16 v0 = (tsf & 0x000000000000FFFFULL); @@ -330,11 +339,14 @@ void bcm43xx_tsf_write(struct bcm43xx_private *bcm, u64 tsf) u16 v2 = (tsf & 0x0000FFFF00000000ULL) >> 32; u16 v3 = (tsf & 0xFFFF000000000000ULL) >> 48; - barrier(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, 0); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_3, v3); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_2, v2); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_1, v1); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_TSF_0, v0); } @@ -974,6 +986,7 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) { struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm->current_core->radio; unsigned int i, max_loop; u16 value = 0; u32 buffer[5] = { @@ -984,6 +997,13 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) 0x00000000, }; +/* FIXME: It seems like a dummy_transmission corrupts the DMA engines, + * once they are initialized. So avoid doing a dummy_transmission, + * if the DMA engines are running. + */ +if (bcm->initialized) +return; + switch (phy->type) { case BCM43xx_PHYTYPE_A: max_loop = 0x1E; @@ -1015,24 +1035,28 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) bcm43xx_write16(bcm, 0x0500, 0x0000); bcm43xx_write16(bcm, 0x0502, 0x0030); + if (radio->version == 0x2050 && radio->revision <= 0x5) + bcm43xx_radio_write16(bcm, 0x0051, 0x0017); for (i = 0x00; i < max_loop; i++) { value = bcm43xx_read16(bcm, 0x050E); - if ((value & 0x0080) != 0) + if (value & 0x0080) break; udelay(10); } for (i = 0x00; i < 0x0A; i++) { value = bcm43xx_read16(bcm, 0x050E); - if ((value & 0x0400) != 0) + if (value & 0x0400) break; udelay(10); } for (i = 0x00; i < 0x0A; i++) { value = bcm43xx_read16(bcm, 0x0690); - if ((value & 0x0100) == 0) + if (!(value & 0x0100)) break; udelay(10); } + if (radio->version == 0x2050 && radio->revision <= 0x5) + bcm43xx_radio_write16(bcm, 0x0051, 0x0037); } static void key_write(struct bcm43xx_private *bcm, @@ -1646,22 +1670,6 @@ static void handle_irq_beacon(struct bcm43xx_private *bcm) } } -/* Debug helper for irq bottom-half to print all reason registers. */ -#define bcmirq_print_reasons(description) \ - do { \ - dprintkl(KERN_ERR PFX description "\n" \ - KERN_ERR PFX " Generic Reason: 0x%08x\n" \ - KERN_ERR PFX " DMA reasons: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n" \ - KERN_ERR PFX " DMA TX status: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n", \ - reason, \ - dma_reason[0], dma_reason[1], \ - dma_reason[2], dma_reason[3], \ - bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_BASE + BCM43xx_DMA_TX_STATUS), \ - bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_BASE + BCM43xx_DMA_TX_STATUS), \ - bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_BASE + BCM43xx_DMA_TX_STATUS), \ - bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_BASE + BCM43xx_DMA_TX_STATUS)); \ - } while (0) - /* Interrupt handler bottom-half */ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) { @@ -1690,9 +1698,30 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) * on DMA or PIO queues. * Maybe we get this in other error conditions, too. */ - bcmirq_print_reasons("XMIT ERROR"); + printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n"); bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR); } + if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_FATALMASK) | + (dma_reason[1] & BCM43xx_DMAIRQ_FATALMASK) | + (dma_reason[2] & BCM43xx_DMAIRQ_FATALMASK) | + (dma_reason[3] & BCM43xx_DMAIRQ_FATALMASK))) { + printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: " + "0x%08X, 0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3]); + bcm43xx_controller_restart(bcm, "DMA error"); + bcm43xx_unlock_mmio(bcm, flags); + return; + } + if (unlikely((dma_reason[0] & BCM43xx_DMAIRQ_NONFATALMASK) | + (dma_reason[1] & BCM43xx_DMAIRQ_NONFATALMASK) | + (dma_reason[2] & BCM43xx_DMAIRQ_NONFATALMASK) | + (dma_reason[3] & BCM43xx_DMAIRQ_NONFATALMASK))) { + printkl(KERN_ERR PFX "DMA error: " + "0x%08X, 0x%08X, 0x%08X, 0x%08X\n", + dma_reason[0], dma_reason[1], + dma_reason[2], dma_reason[3]); + } if (reason & BCM43xx_IRQ_PS) { handle_irq_ps(bcm); @@ -1780,8 +1809,6 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) bcm43xx_unlock_mmio(bcm, flags); } -#undef bcmirq_print_reasons - static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason, u32 mask) { @@ -3875,6 +3902,7 @@ failure: void bcm43xx_controller_restart(struct bcm43xx_private *bcm, const char *reason) { bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ printk(KERN_ERR PFX "Controller RESET (%s) ...\n", reason); INIT_WORK(&bcm->restart_work, bcm43xx_chip_reset, bcm); schedule_work(&bcm->restart_work); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index d3c2fc1df37..dbbef6ccd15 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -126,6 +126,7 @@ u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset) void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val) { bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_CONTROL, offset); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_DATA, val); } @@ -255,16 +256,16 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) if (phy->rev == 1) offset = 0x4C00; - bcm43xx_ilt_write16(bcm, offset, 0x00FE); - bcm43xx_ilt_write16(bcm, offset + 1, 0x000D); - bcm43xx_ilt_write16(bcm, offset + 2, 0x0013); - bcm43xx_ilt_write16(bcm, offset + 3, 0x0019); + bcm43xx_ilt_write(bcm, offset, 0x00FE); + bcm43xx_ilt_write(bcm, offset + 1, 0x000D); + bcm43xx_ilt_write(bcm, offset + 2, 0x0013); + bcm43xx_ilt_write(bcm, offset + 3, 0x0019); if (phy->rev == 1) { - bcm43xx_ilt_write16(bcm, 0x1800, 0x2710); - bcm43xx_ilt_write16(bcm, 0x1801, 0x9B83); - bcm43xx_ilt_write16(bcm, 0x1802, 0x9B83); - bcm43xx_ilt_write16(bcm, 0x1803, 0x0F8D); + bcm43xx_ilt_write(bcm, 0x1800, 0x2710); + bcm43xx_ilt_write(bcm, 0x1801, 0x9B83); + bcm43xx_ilt_write(bcm, 0x1802, 0x9B83); + bcm43xx_ilt_write(bcm, 0x1803, 0x0F8D); bcm43xx_phy_write(bcm, 0x0455, 0x0004); } @@ -317,10 +318,10 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x048D, 0x0002); } - bcm43xx_ilt_write16(bcm, offset + 0x0800, 0); - bcm43xx_ilt_write16(bcm, offset + 0x0801, 7); - bcm43xx_ilt_write16(bcm, offset + 0x0802, 16); - bcm43xx_ilt_write16(bcm, offset + 0x0803, 28); + bcm43xx_ilt_write(bcm, offset + 0x0800, 0); + bcm43xx_ilt_write(bcm, offset + 0x0801, 7); + bcm43xx_ilt_write(bcm, offset + 0x0802, 16); + bcm43xx_ilt_write(bcm, offset + 0x0803, 28); } static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) @@ -337,11 +338,11 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0427, 0x001A); for (i = 0; i < BCM43xx_ILT_FINEFREQG_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]); + bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqg[i]); for (i = 0; i < BCM43xx_ILT_NOISEG1_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]); + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg1[i]); for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); + bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); } else { /* nrssi values are signed 6-bit values. Not sure why we write 0x7654 here... */ bcm43xx_nrssi_hw_write(bcm, 0xBA98, (s16)0x7654); @@ -357,36 +358,36 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x800); for (i = 0; i < 64; i++) - bcm43xx_ilt_write16(bcm, 0x4000 + i, i); + bcm43xx_ilt_write(bcm, 0x4000 + i, i); for (i = 0; i < BCM43xx_ILT_NOISEG2_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noiseg2[i]); + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noiseg2[i]); } if (phy->rev <= 2) for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]); + bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]); else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200)) for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]); + bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]); else for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg2[i]); + bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg2[i]); if (phy->rev == 2) for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); + bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); else if ((phy->rev > 2) && (phy->rev <= 7)) for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]); + bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]); if (phy->rev == 1) { for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); + bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); for (i = 0; i < 4; i++) { - bcm43xx_ilt_write16(bcm, 0x5404 + i, 0x0020); - bcm43xx_ilt_write16(bcm, 0x5408 + i, 0x0020); - bcm43xx_ilt_write16(bcm, 0x540C + i, 0x0020); - bcm43xx_ilt_write16(bcm, 0x5410 + i, 0x0020); + bcm43xx_ilt_write(bcm, 0x5404 + i, 0x0020); + bcm43xx_ilt_write(bcm, 0x5408 + i, 0x0020); + bcm43xx_ilt_write(bcm, 0x540C + i, 0x0020); + bcm43xx_ilt_write(bcm, 0x5410 + i, 0x0020); } bcm43xx_phy_agcsetup(bcm); @@ -395,24 +396,24 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) (bcm->board_revision == 0x0017)) return; - bcm43xx_ilt_write16(bcm, 0x5001, 0x0002); - bcm43xx_ilt_write16(bcm, 0x5002, 0x0001); + bcm43xx_ilt_write(bcm, 0x5001, 0x0002); + bcm43xx_ilt_write(bcm, 0x5002, 0x0001); } else { for (i = 0; i <= 0x2F; i++) - bcm43xx_ilt_write16(bcm, 0x1000 + i, 0x0820); + bcm43xx_ilt_write(bcm, 0x1000 + i, 0x0820); bcm43xx_phy_agcsetup(bcm); bcm43xx_phy_read(bcm, 0x0400); /* dummy read */ bcm43xx_phy_write(bcm, 0x0403, 0x1000); - bcm43xx_ilt_write16(bcm, 0x3C02, 0x000F); - bcm43xx_ilt_write16(bcm, 0x3C03, 0x0014); + bcm43xx_ilt_write(bcm, 0x3C02, 0x000F); + bcm43xx_ilt_write(bcm, 0x3C03, 0x0014); if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && (bcm->board_type == 0x0416) && (bcm->board_revision == 0x0017)) return; - bcm43xx_ilt_write16(bcm, 0x0401, 0x0002); - bcm43xx_ilt_write16(bcm, 0x0402, 0x0001); + bcm43xx_ilt_write(bcm, 0x0401, 0x0002); + bcm43xx_ilt_write(bcm, 0x0402, 0x0001); } } @@ -456,11 +457,11 @@ static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x0035, 0x03FF); bcm43xx_phy_write(bcm, 0x0036, 0x0400); - bcm43xx_ilt_write16(bcm, 0x3807, 0x0051); + bcm43xx_ilt_write(bcm, 0x3807, 0x0051); bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); - bcm43xx_ilt_write16(bcm, 0x3C0C, 0x07BF); + bcm43xx_ilt_write(bcm, 0x3C0C, 0x07BF); bcm43xx_radio_write16(bcm, 0x0002, 0x07BF); bcm43xx_phy_write(bcm, 0x0024, 0x4680); @@ -472,47 +473,47 @@ static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x002B, bcm43xx_phy_read(bcm, 0x002B) & 0xFBFF); bcm43xx_phy_write(bcm, 0x008E, 0x58C1); - bcm43xx_ilt_write16(bcm, 0x0803, 0x000F); - bcm43xx_ilt_write16(bcm, 0x0804, 0x001F); - bcm43xx_ilt_write16(bcm, 0x0805, 0x002A); - bcm43xx_ilt_write16(bcm, 0x0805, 0x0030); - bcm43xx_ilt_write16(bcm, 0x0807, 0x003A); + bcm43xx_ilt_write(bcm, 0x0803, 0x000F); + bcm43xx_ilt_write(bcm, 0x0804, 0x001F); + bcm43xx_ilt_write(bcm, 0x0805, 0x002A); + bcm43xx_ilt_write(bcm, 0x0805, 0x0030); + bcm43xx_ilt_write(bcm, 0x0807, 0x003A); - bcm43xx_ilt_write16(bcm, 0x0000, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0001, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0002, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0003, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0004, 0x0015); - bcm43xx_ilt_write16(bcm, 0x0005, 0x0015); - bcm43xx_ilt_write16(bcm, 0x0006, 0x0019); + bcm43xx_ilt_write(bcm, 0x0000, 0x0013); + bcm43xx_ilt_write(bcm, 0x0001, 0x0013); + bcm43xx_ilt_write(bcm, 0x0002, 0x0013); + bcm43xx_ilt_write(bcm, 0x0003, 0x0013); + bcm43xx_ilt_write(bcm, 0x0004, 0x0015); + bcm43xx_ilt_write(bcm, 0x0005, 0x0015); + bcm43xx_ilt_write(bcm, 0x0006, 0x0019); - bcm43xx_ilt_write16(bcm, 0x0404, 0x0003); - bcm43xx_ilt_write16(bcm, 0x0405, 0x0003); - bcm43xx_ilt_write16(bcm, 0x0406, 0x0007); + bcm43xx_ilt_write(bcm, 0x0404, 0x0003); + bcm43xx_ilt_write(bcm, 0x0405, 0x0003); + bcm43xx_ilt_write(bcm, 0x0406, 0x0007); for (i = 0; i < 16; i++) - bcm43xx_ilt_write16(bcm, 0x4000 + i, (0x8 + i) & 0x000F); + bcm43xx_ilt_write(bcm, 0x4000 + i, (0x8 + i) & 0x000F); - bcm43xx_ilt_write16(bcm, 0x3003, 0x1044); - bcm43xx_ilt_write16(bcm, 0x3004, 0x7201); - bcm43xx_ilt_write16(bcm, 0x3006, 0x0040); - bcm43xx_ilt_write16(bcm, 0x3001, (bcm43xx_ilt_read16(bcm, 0x3001) & 0x0010) | 0x0008); + bcm43xx_ilt_write(bcm, 0x3003, 0x1044); + bcm43xx_ilt_write(bcm, 0x3004, 0x7201); + bcm43xx_ilt_write(bcm, 0x3006, 0x0040); + bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008); for (i = 0; i < BCM43xx_ILT_FINEFREQA_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]); + bcm43xx_ilt_write(bcm, 0x5800 + i, bcm43xx_ilt_finefreqa[i]); for (i = 0; i < BCM43xx_ILT_NOISEA2_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]); + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea2[i]); for (i = 0; i < BCM43xx_ILT_ROTOR_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); + bcm43xx_ilt_write(bcm, 0x2000 + i, bcm43xx_ilt_rotor[i]); bcm43xx_phy_init_noisescaletbl(bcm); for (i = 0; i < BCM43xx_ILT_RETARD_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); + bcm43xx_ilt_write(bcm, 0x2400 + i, bcm43xx_ilt_retard[i]); break; case 3: for (i = 0; i < 64; i++) - bcm43xx_ilt_write16(bcm, 0x4000 + i, i); + bcm43xx_ilt_write(bcm, 0x4000 + i, i); - bcm43xx_ilt_write16(bcm, 0x3807, 0x0051); + bcm43xx_ilt_write(bcm, 0x3807, 0x0051); bcm43xx_phy_write(bcm, 0x001C, 0x0FF9); bcm43xx_phy_write(bcm, 0x0020, bcm43xx_phy_read(bcm, 0x0020) & 0xFF0F); @@ -524,35 +525,35 @@ static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x001F, 0x1C00); bcm43xx_phy_write(bcm, 0x002A, (bcm43xx_phy_read(bcm, 0x002A) & 0x00FF) | 0x0400); - bcm43xx_ilt_write16(bcm, 0x3001, (bcm43xx_ilt_read16(bcm, 0x3001) & 0x0010) | 0x0008); + bcm43xx_ilt_write(bcm, 0x3001, (bcm43xx_ilt_read(bcm, 0x3001) & 0x0010) | 0x0008); for (i = 0; i < BCM43xx_ILT_NOISEA3_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x1800 + i, bcm43xx_ilt_noisea3[i]); + bcm43xx_ilt_write(bcm, 0x1800 + i, bcm43xx_ilt_noisea3[i]); bcm43xx_phy_init_noisescaletbl(bcm); for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++) - bcm43xx_ilt_write16(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); + bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]); bcm43xx_phy_write(bcm, 0x0003, 0x1808); - bcm43xx_ilt_write16(bcm, 0x0803, 0x000F); - bcm43xx_ilt_write16(bcm, 0x0804, 0x001F); - bcm43xx_ilt_write16(bcm, 0x0805, 0x002A); - bcm43xx_ilt_write16(bcm, 0x0805, 0x0030); - bcm43xx_ilt_write16(bcm, 0x0807, 0x003A); - - bcm43xx_ilt_write16(bcm, 0x0000, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0001, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0002, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0003, 0x0013); - bcm43xx_ilt_write16(bcm, 0x0004, 0x0015); - bcm43xx_ilt_write16(bcm, 0x0005, 0x0015); - bcm43xx_ilt_write16(bcm, 0x0006, 0x0019); - - bcm43xx_ilt_write16(bcm, 0x0404, 0x0003); - bcm43xx_ilt_write16(bcm, 0x0405, 0x0003); - bcm43xx_ilt_write16(bcm, 0x0406, 0x0007); - - bcm43xx_ilt_write16(bcm, 0x3C02, 0x000F); - bcm43xx_ilt_write16(bcm, 0x3C03, 0x0014); + bcm43xx_ilt_write(bcm, 0x0803, 0x000F); + bcm43xx_ilt_write(bcm, 0x0804, 0x001F); + bcm43xx_ilt_write(bcm, 0x0805, 0x002A); + bcm43xx_ilt_write(bcm, 0x0805, 0x0030); + bcm43xx_ilt_write(bcm, 0x0807, 0x003A); + + bcm43xx_ilt_write(bcm, 0x0000, 0x0013); + bcm43xx_ilt_write(bcm, 0x0001, 0x0013); + bcm43xx_ilt_write(bcm, 0x0002, 0x0013); + bcm43xx_ilt_write(bcm, 0x0003, 0x0013); + bcm43xx_ilt_write(bcm, 0x0004, 0x0015); + bcm43xx_ilt_write(bcm, 0x0005, 0x0015); + bcm43xx_ilt_write(bcm, 0x0006, 0x0019); + + bcm43xx_ilt_write(bcm, 0x0404, 0x0003); + bcm43xx_ilt_write(bcm, 0x0405, 0x0003); + bcm43xx_ilt_write(bcm, 0x0406, 0x0007); + + bcm43xx_ilt_write(bcm, 0x3C02, 0x000F); + bcm43xx_ilt_write(bcm, 0x3C03, 0x0014); break; default: assert(0); @@ -598,19 +599,19 @@ static void bcm43xx_phy_inita(struct bcm43xx_private *bcm) bcm43xx_radio_write16(bcm, 0x0019, 0x0000); bcm43xx_radio_write16(bcm, 0x0017, 0x0020); - tval = bcm43xx_ilt_read16(bcm, 0x3001); + tval = bcm43xx_ilt_read(bcm, 0x3001); if (phy->rev == 1) { - bcm43xx_ilt_write16(bcm, 0x3001, - (bcm43xx_ilt_read16(bcm, 0x3001) & 0xFF87) - | 0x0058); + bcm43xx_ilt_write(bcm, 0x3001, + (bcm43xx_ilt_read(bcm, 0x3001) & 0xFF87) + | 0x0058); } else { - bcm43xx_ilt_write16(bcm, 0x3001, - (bcm43xx_ilt_read16(bcm, 0x3001) & 0xFFC3) - | 0x002C); + bcm43xx_ilt_write(bcm, 0x3001, + (bcm43xx_ilt_read(bcm, 0x3001) & 0xFFC3) + | 0x002C); } bcm43xx_dummy_transmission(bcm); phy->savedpctlreg = bcm43xx_phy_read(bcm, BCM43xx_PHY_A_PCTL); - bcm43xx_ilt_write16(bcm, 0x3001, tval); + bcm43xx_ilt_write(bcm, 0x3001, tval); bcm43xx_radio_set_txpower_a(bcm, 0x0018); } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 3901aa99466..4d3b0e85876 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -97,6 +97,7 @@ void bcm43xx_radio_lock(struct bcm43xx_private *bcm) status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); status |= BCM43xx_SBF_RADIOREG_LOCK; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + mmiowb(); udelay(10); } @@ -108,6 +109,7 @@ void bcm43xx_radio_unlock(struct bcm43xx_private *bcm) status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); status &= ~BCM43xx_SBF_RADIOREG_LOCK; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); + mmiowb(); } u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset) @@ -142,6 +144,7 @@ u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset) void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val) { bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, offset); + mmiowb(); bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW, val); } @@ -161,10 +164,10 @@ static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm, } for (i = 0; i < 4; i++) - bcm43xx_ilt_write16(bcm, offset + i, first); + bcm43xx_ilt_write(bcm, offset + i, first); for (i = start; i < end; i++) - bcm43xx_ilt_write16(bcm, offset + i, second); + bcm43xx_ilt_write(bcm, offset + i, second); if (third != -1) { tmp = ((u16)third << 14) | ((u16)third << 6); @@ -196,11 +199,11 @@ static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm) tmp |= (i & 0x0001) << 1; tmp |= (i & 0x0002) >> 1; - bcm43xx_ilt_write16(bcm, offset + i, tmp); + bcm43xx_ilt_write(bcm, offset + i, tmp); } for (i = start; i < end; i++) - bcm43xx_ilt_write16(bcm, offset + i, i - start); + bcm43xx_ilt_write(bcm, offset + i, i - start); bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xBFBF) | 0x4040); @@ -316,6 +319,7 @@ u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm) void bcm43xx_nrssi_hw_write(struct bcm43xx_private *bcm, u16 offset, s16 val) { bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_CTRL, offset); + mmiowb(); bcm43xx_phy_write(bcm, BCM43xx_PHY_NRSSILT_DATA, (u16)val); } @@ -612,10 +616,6 @@ void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm) } break; case BCM43xx_PHYTYPE_G: -//FIXME: Something is broken here. This is called when enabling WLAN interfmode. -// If this is done at runtime, I get an XMIT ERROR and transmission is -// broken. I guess some important register is overwritten by accident. -// The XMIT ERROR comes from the dummy_transmissions in set_gains. if (radio->revision >= 9) return; if (radio->revision == 8) @@ -1641,14 +1641,14 @@ void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower) base &= 0x000F; bcm43xx_phy_write(bcm, 0x0017, base | 0x0020); - ilt = bcm43xx_ilt_read16(bcm, 0x3001); + ilt = bcm43xx_ilt_read(bcm, 0x3001); ilt &= 0x0007; dac = bcm43xx_get_txgain_dac(txpower); dac <<= 3; dac |= ilt; - bcm43xx_ilt_write16(bcm, 0x3001, dac); + bcm43xx_ilt_write(bcm, 0x3001, dac); bcm->current_core->radio->txpower[0] = txpower; -- cgit v1.2.3 From e1b1b581b847a5ae9409a02a586476eaba2b3f89 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 13 Mar 2006 15:20:05 +0100 Subject: [PATCH] bcm43xx: receive TX status on MMIO or DMA unconditionally regarding the 80211 core rev. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index a563258cad3..3ab02f4f8ec 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1765,22 +1765,17 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) /* We intentionally don't set "activity" to 1, here. */ } if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { - if (likely(bcm->current_core->rev < 5)) { - if (bcm43xx_using_pio(bcm)) - bcm43xx_pio_rx(bcm->current_core->pio->queue3); - else - bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1); - activity = 1; - } else - assert(0); + if (bcm43xx_using_pio(bcm)) + bcm43xx_pio_rx(bcm->current_core->pio->queue3); + else + bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1); + activity = 1; } bcmirq_handled(BCM43xx_IRQ_RX); if (reason & BCM43xx_IRQ_XMIT_STATUS) { - if (bcm->current_core->rev >= 5) { - handle_irq_transmit_status(bcm); - activity = 1; - } + handle_irq_transmit_status(bcm); + activity = 1; //TODO: In AP mode, this also causes sending of powersave responses. bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS); } -- cgit v1.2.3 From aae3778176ec7a57b1c4f539b7252acfd7d99a1b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 13 Mar 2006 15:54:56 +0100 Subject: [PATCH] bcm43xx: add functions bcm43xx_dma_read/write, bcm43xx_dma_tx_suspend/resume. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 61 ++++++++++++++++-------------- drivers/net/wireless/bcm43xx/bcm43xx_dma.h | 18 +++++++++ 2 files changed, 51 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index 0cd29284795..fbe19b922aa 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -374,13 +374,11 @@ static int dmacontroller_setup(struct bcm43xx_dmaring *ring) if (ring->tx) { /* Set Transmit Control register to "transmit enable" */ - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_TX_CONTROL, - BCM43xx_DMA_TXCTRL_ENABLE); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, + BCM43xx_DMA_TXCTRL_ENABLE); /* Set Transmit Descriptor ring address. */ - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_TX_DESC_RING, - ring->dmabase + ring->memoffset); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, + ring->dmabase + ring->memoffset); } else { err = alloc_initial_descbuffers(ring); if (err) @@ -388,17 +386,12 @@ static int dmacontroller_setup(struct bcm43xx_dmaring *ring) /* Set Receive Control "receive enable" and frame offset */ value = (ring->frameoffset << BCM43xx_DMA_RXCTRL_FRAMEOFF_SHIFT); value |= BCM43xx_DMA_RXCTRL_ENABLE; - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_RX_CONTROL, - value); + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_CONTROL, value); /* Set Receive Descriptor ring address. */ - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_RX_DESC_RING, - ring->dmabase + ring->memoffset); + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, + ring->dmabase + ring->memoffset); /* Init the descriptor pointer. */ - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_RX_DESC_INDEX, - 200); + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, 200); } out: @@ -411,15 +404,11 @@ static void dmacontroller_cleanup(struct bcm43xx_dmaring *ring) if (ring->tx) { bcm43xx_dmacontroller_tx_reset(ring->bcm, ring->mmio_base); /* Zero out Transmit Descriptor ring address. */ - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_TX_DESC_RING, - 0x00000000); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_RING, 0); } else { bcm43xx_dmacontroller_rx_reset(ring->bcm, ring->mmio_base); /* Zero out Receive Descriptor ring address. */ - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_RX_DESC_RING, - 0x00000000); + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_RING, 0); } } @@ -698,9 +687,8 @@ static void dmacontroller_poke_tx(struct bcm43xx_dmaring *ring, */ wmb(); slot = next_slot(ring, slot); - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_TX_DESC_INDEX, - (u32)(slot * sizeof(struct bcm43xx_dmadesc))); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_DESC_INDEX, + (u32)(slot * sizeof(struct bcm43xx_dmadesc))); } static int dma_tx_fragment(struct bcm43xx_dmaring *ring, @@ -940,7 +928,7 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) #endif assert(!ring->tx); - status = bcm43xx_read32(ring->bcm, ring->mmio_base + BCM43xx_DMA_RX_STATUS); + status = bcm43xx_dma_read(ring, BCM43xx_DMA_RX_STATUS); descptr = (status & BCM43xx_DMA_RXSTAT_DPTR_MASK); current_slot = descptr / sizeof(struct bcm43xx_dmadesc); assert(current_slot >= 0 && current_slot < ring->nr_slots); @@ -953,10 +941,27 @@ void bcm43xx_dma_rx(struct bcm43xx_dmaring *ring) ring->max_used_slots = used_slots; #endif } - bcm43xx_write32(ring->bcm, - ring->mmio_base + BCM43xx_DMA_RX_DESC_INDEX, - (u32)(slot * sizeof(struct bcm43xx_dmadesc))); + bcm43xx_dma_write(ring, BCM43xx_DMA_RX_DESC_INDEX, + (u32)(slot * sizeof(struct bcm43xx_dmadesc))); ring->current_slot = slot; } +void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring) +{ + assert(ring->tx); + bcm43xx_power_saving_ctl_bits(ring->bcm, -1, 1); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, + bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL) + | BCM43xx_DMA_TXCTRL_SUSPEND); +} + +void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring) +{ + assert(ring->tx); + bcm43xx_dma_write(ring, BCM43xx_DMA_TX_CONTROL, + bcm43xx_dma_read(ring, BCM43xx_DMA_TX_CONTROL) + & ~BCM43xx_DMA_TXCTRL_SUSPEND); + bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1); +} + /* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h index c07e34689be..2d520e4b027 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.h @@ -140,6 +140,21 @@ struct bcm43xx_dmaring { }; +static inline +u32 bcm43xx_dma_read(struct bcm43xx_dmaring *ring, + u16 offset) +{ + return bcm43xx_read32(ring->bcm, ring->mmio_base + offset); +} + +static inline +void bcm43xx_dma_write(struct bcm43xx_dmaring *ring, + u16 offset, u32 value) +{ + bcm43xx_write32(ring->bcm, ring->mmio_base + offset, value); +} + + int bcm43xx_dma_init(struct bcm43xx_private *bcm); void bcm43xx_dma_free(struct bcm43xx_private *bcm); @@ -148,6 +163,9 @@ int bcm43xx_dmacontroller_rx_reset(struct bcm43xx_private *bcm, int bcm43xx_dmacontroller_tx_reset(struct bcm43xx_private *bcm, u16 dmacontroller_mmio_base); +void bcm43xx_dma_tx_suspend(struct bcm43xx_dmaring *ring); +void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring); + void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, struct bcm43xx_xmitstatus *status); -- cgit v1.2.3 From e9357c056c5e62516f0044e60591d41f00ca7cfa Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 13 Mar 2006 19:27:34 +0100 Subject: [PATCH] bcm43xx: reduce the size of bcm43xx_private by removing unneeded members. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 94 ++++++---- drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 7 +- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 9 +- drivers/net/wireless/bcm43xx/bcm43xx_ilt.c | 4 +- drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 4 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 238 ++++++++++++------------- drivers/net/wireless/bcm43xx/bcm43xx_main.h | 6 +- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 128 ++++++------- drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 8 +- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 72 ++++---- drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 35 ++-- drivers/net/wireless/bcm43xx/bcm43xx_xmit.c | 14 +- 13 files changed, 320 insertions(+), 301 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 29c95b07122..a358646ad3e 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -556,33 +556,37 @@ struct bcm43xx_pio { #define BCM43xx_MAX_80211_CORES 2 -#define BCM43xx_COREFLAG_AVAILABLE (1 << 0) -#define BCM43xx_COREFLAG_ENABLED (1 << 1) -#define BCM43xx_COREFLAG_INITIALIZED (1 << 2) - #ifdef CONFIG_BCM947XX #define core_offset(bcm) (bcm)->current_core_offset #else #define core_offset(bcm) 0 #endif +/* Generic information about a core. */ struct bcm43xx_coreinfo { - /** Driver internal flags. See BCM43xx_COREFLAG_* */ - u32 flags; + u8 available:1, + enabled:1, + initialized:1; /** core_id ID number */ u16 id; /** core_rev revision number */ u8 rev; /** Index number for _switch_core() */ u8 index; - /* Pointer to the PHYinfo, which belongs to this core (if 80211 core) */ - struct bcm43xx_phyinfo *phy; - /* Pointer to the RadioInfo, which belongs to this core (if 80211 core) */ - struct bcm43xx_radioinfo *radio; - /* Pointer to the DMA rings, which belong to this core (if 80211 core) */ - struct bcm43xx_dma *dma; - /* Pointer to the PIO queues, which belong to this core (if 80211 core) */ - struct bcm43xx_pio *pio; +}; + +/* Additional information for each 80211 core. */ +struct bcm43xx_coreinfo_80211 { + /* PHY device. */ + struct bcm43xx_phyinfo phy; + /* Radio device. */ + struct bcm43xx_radioinfo radio; + union { + /* DMA context. */ + struct bcm43xx_dma dma; + /* PIO context. */ + struct bcm43xx_pio pio; + }; }; /* Context information for a noise calculation (Link Quality). */ @@ -652,7 +656,7 @@ struct bcm43xx_private { #define BCM43xx_NR_LEDS 4 struct bcm43xx_led leds[BCM43xx_NR_LEDS]; - /* The currently active core. NULL if not initialized, yet. */ + /* The currently active core. */ struct bcm43xx_coreinfo *current_core; #ifdef CONFIG_BCM947XX /** current core memory offset */ @@ -665,18 +669,15 @@ struct bcm43xx_private { */ struct bcm43xx_coreinfo core_chipcommon; struct bcm43xx_coreinfo core_pci; - struct bcm43xx_coreinfo core_v90; - struct bcm43xx_coreinfo core_pcmcia; - struct bcm43xx_coreinfo core_ethernet; struct bcm43xx_coreinfo core_80211[ BCM43xx_MAX_80211_CORES ]; - /* Info about the PHY for each 80211 core. */ - struct bcm43xx_phyinfo phy[ BCM43xx_MAX_80211_CORES ]; - /* Info about the Radio for each 80211 core. */ - struct bcm43xx_radioinfo radio[ BCM43xx_MAX_80211_CORES ]; - /* DMA */ - struct bcm43xx_dma dma[ BCM43xx_MAX_80211_CORES ]; - /* PIO */ - struct bcm43xx_pio pio[ BCM43xx_MAX_80211_CORES ]; + /* Additional information, specific to the 80211 cores. */ + struct bcm43xx_coreinfo_80211 core_80211_ext[ BCM43xx_MAX_80211_CORES ]; + /* Index of the current 80211 core. If current_core is not + * an 80211 core, this is -1. + */ + int current_80211_core_idx; + /* Number of available 80211 cores. */ + int nr_80211_available; u32 chipcommon_capabilities; @@ -769,18 +770,39 @@ int bcm43xx_using_pio(struct bcm43xx_private *bcm) # error "Using neither DMA nor PIO? Confused..." #endif - +/* Helper functions to access data structures private to the 80211 cores. + * Note that we _must_ have an 80211 core mapped when calling + * any of these functions. + */ static inline -int bcm43xx_num_80211_cores(struct bcm43xx_private *bcm) +struct bcm43xx_pio * bcm43xx_current_pio(struct bcm43xx_private *bcm) { - int i, cnt = 0; - - for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { - if (bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE) - cnt++; - } - - return cnt; + assert(bcm43xx_using_pio(bcm)); + assert(bcm->current_80211_core_idx >= 0); + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].pio); +} +static inline +struct bcm43xx_dma * bcm43xx_current_dma(struct bcm43xx_private *bcm) +{ + assert(!bcm43xx_using_pio(bcm)); + assert(bcm->current_80211_core_idx >= 0); + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].dma); +} +static inline +struct bcm43xx_phyinfo * bcm43xx_current_phy(struct bcm43xx_private *bcm) +{ + assert(bcm->current_80211_core_idx >= 0); + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].phy); +} +static inline +struct bcm43xx_radioinfo * bcm43xx_current_radio(struct bcm43xx_private *bcm) +{ + assert(bcm->current_80211_core_idx >= 0); + assert(bcm->current_80211_core_idx < BCM43xx_MAX_80211_CORES); + return &(bcm->core_80211_ext[bcm->current_80211_core_idx].radio); } /* Are we running in init_board() context? */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index bcfcebe2826..f73d36b8e0f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -104,16 +104,13 @@ static ssize_t devinfo_read_file(struct file *file, char __user *userbuf, fappend("\nCores:\n"); #define fappend_core(name, info) fappend("core \"" name "\" %s, %s, id: 0x%04x, " \ "rev: 0x%02x, index: 0x%02x\n", \ - (info).flags & BCM43xx_COREFLAG_AVAILABLE \ + (info).available \ ? "available" : "nonavailable", \ - (info).flags & BCM43xx_COREFLAG_ENABLED \ + (info).enabled \ ? "enabled" : "disabled", \ (info).id, (info).rev, (info).index) fappend_core("CHIPCOMMON", bcm->core_chipcommon); fappend_core("PCI", bcm->core_pci); - fappend_core("V90", bcm->core_v90); - fappend_core("PCMCIA", bcm->core_pcmcia); - fappend_core("ETHERNET", bcm->core_ethernet); fappend_core("first 80211", bcm->core_80211[0]); fappend_core("second 80211", bcm->core_80211[1]); #undef fappend_core diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index fbe19b922aa..7ed368a587f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -531,7 +531,7 @@ static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring) void bcm43xx_dma_free(struct bcm43xx_private *bcm) { - struct bcm43xx_dma *dma = bcm->current_core->dma; + struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); bcm43xx_destroy_dmaring(dma->rx_ring1); dma->rx_ring1 = NULL; @@ -549,7 +549,7 @@ void bcm43xx_dma_free(struct bcm43xx_private *bcm) int bcm43xx_dma_init(struct bcm43xx_private *bcm) { - struct bcm43xx_dma *dma = bcm->current_core->dma; + struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); struct bcm43xx_dmaring *ring; int err = -ENOMEM; @@ -652,7 +652,7 @@ static struct bcm43xx_dmaring * parse_cookie(struct bcm43xx_private *bcm, u16 cookie, int *slot) { - struct bcm43xx_dma *dma = bcm->current_core->dma; + struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); struct bcm43xx_dmaring *ring = NULL; switch (cookie & 0xF000) { @@ -755,7 +755,7 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, * the device to send the stuff. * Note that this is called from atomic context. */ - struct bcm43xx_dmaring *ring = bcm->current_core->dma->tx_ring1; + struct bcm43xx_dmaring *ring = bcm43xx_current_dma(bcm)->tx_ring1; u8 i; struct sk_buff *skb; @@ -784,6 +784,7 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, struct bcm43xx_xmitstatus *status) { + struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); struct bcm43xx_dmaring *ring; struct bcm43xx_dmadesc *desc; struct bcm43xx_dmadesc_meta *meta; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c index 865ed5c3361..ad8e569d1fa 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ilt.c @@ -314,7 +314,7 @@ const u16 bcm43xx_ilt_sigmasqr2[BCM43xx_ILT_SIGMASQR_SIZE] = { void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val) { - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) { bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); mmiowb(); bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_DATA1, val); @@ -327,7 +327,7 @@ void bcm43xx_ilt_write(struct bcm43xx_private *bcm, u16 offset, u16 val) u16 bcm43xx_ilt_read(struct bcm43xx_private *bcm, u16 offset) { - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) { + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) { bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, offset); return bcm43xx_phy_read(bcm, BCM43xx_PHY_ILT_A_DATA1); } else { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index 949555da5aa..72a243aac6c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -171,8 +171,8 @@ void bcm43xx_leds_exit(struct bcm43xx_private *bcm) void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) { struct bcm43xx_led *led; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES; int i, turn_on; unsigned long interval = 0; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 3ab02f4f8ec..88e9a125c2d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -406,7 +406,7 @@ static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm) static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) { /* slot_time is in usec. */ - if (bcm->current_core->phy->type != BCM43xx_PHYTYPE_G) + if (bcm43xx_current_phy(bcm)->type != BCM43xx_PHYTYPE_G) return; bcm43xx_write16(bcm, 0x684, 510 + slot_time); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0010, slot_time); @@ -443,7 +443,7 @@ static void bcm43xx_disassociate(struct bcm43xx_private *bcm) bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0004, 0x000003ff); - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G && + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G && ieee80211_is_ofdm_rate(bcm->softmac->txrates.default_rate)) bcm43xx_short_slot_timing_enable(bcm); @@ -510,8 +510,8 @@ static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *old static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u32 radio_id; u16 manufact; u16 version; @@ -566,10 +566,10 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) radio->txpower[2] = 3; else radio->txpower[2] = 0; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + if (phy->type == BCM43xx_PHYTYPE_A) radio->txpower_desired = bcm->sprom.maxpower_aphy; else - bcm->current_core->radio->txpower_desired = bcm->sprom.maxpower_bgphy; + radio->txpower_desired = bcm->sprom.maxpower_bgphy; /* Initialize the in-memory nrssi Lookup Table. */ for (i = 0; i < 64; i++) @@ -929,15 +929,14 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) struct ieee80211_geo geo; struct ieee80211_channel *chan; int have_a = 0, have_bg = 0; - int i, num80211; + int i; u8 channel; struct bcm43xx_phyinfo *phy; const char *iso_country; memset(&geo, 0, sizeof(geo)); - num80211 = bcm43xx_num_80211_cores(bcm); - for (i = 0; i < num80211; i++) { - phy = bcm->phy + i; + for (i = 0; i < bcm->nr_80211_available; i++) { + phy = &(bcm->core_80211_ext[i].phy); switch (phy->type) { case BCM43xx_PHYTYPE_B: case BCM43xx_PHYTYPE_G: @@ -985,8 +984,8 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm) */ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); unsigned int i, max_loop; u16 value = 0; u32 buffer[5] = { @@ -1213,14 +1212,20 @@ int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *ne if (unlikely(!new_core)) return 0; - if (!(new_core->flags & BCM43xx_COREFLAG_AVAILABLE)) + if (!new_core->available) return -ENODEV; if (bcm->current_core == new_core) return 0; err = _switch_core(bcm, new_core->index); - if (likely(!err)) - bcm->current_core = new_core; + if (unlikely(err)) + goto out; + bcm->current_core = new_core; + bcm->current_80211_core_idx = -1; + if (new_core->id == BCM43xx_COREID_80211) + bcm->current_80211_core_idx = (int)(new_core - &(bcm->core_80211[0])); + +out: return err; } @@ -1295,7 +1300,8 @@ static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags) bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); out: - bcm->current_core->flags &= ~ BCM43xx_COREFLAG_ENABLED; + bcm->current_core->enabled = 0; + return 0; } @@ -1340,7 +1346,7 @@ static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags) bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(1); - bcm->current_core->flags |= BCM43xx_COREFLAG_ENABLED; + bcm->current_core->enabled = 1; assert(err == 0); out: return err; @@ -1411,7 +1417,7 @@ static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm, bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(1); - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_G) { old_core = bcm->current_core; err = bcm43xx_switch_core(bcm, active_80211_core); if (err) @@ -1433,9 +1439,6 @@ static void handle_irq_transmit_status(struct bcm43xx_private *bcm) u16 tmp; struct bcm43xx_xmitstatus stat; - assert(bcm->current_core->id == BCM43xx_COREID_80211); - assert(bcm->current_core->rev >= 5); - while (1) { v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0); if (!v0) @@ -1473,7 +1476,7 @@ static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm) bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4)); assert(bcm->noisecalc.core_at_start == bcm->current_core); - assert(bcm->noisecalc.channel_at_start == bcm->current_core->radio->channel); + assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel); } static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm) @@ -1483,7 +1486,7 @@ static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm) if (bcm->noisecalc.calculation_running) return; bcm->noisecalc.core_at_start = bcm->current_core; - bcm->noisecalc.channel_at_start = bcm->current_core->radio->channel; + bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel; bcm->noisecalc.calculation_running = 1; bcm->noisecalc.nr_samples = 0; @@ -1492,7 +1495,7 @@ static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm) static void handle_irq_noise(struct bcm43xx_private *bcm) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 tmp; u8 noise[4]; u8 i, j; @@ -1759,16 +1762,16 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE)); if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) { if (bcm43xx_using_pio(bcm)) - bcm43xx_pio_rx(bcm->current_core->pio->queue0); + bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0); else - bcm43xx_dma_rx(bcm->current_core->dma->rx_ring0); + bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0); /* We intentionally don't set "activity" to 1, here. */ } if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) { if (bcm43xx_using_pio(bcm)) - bcm43xx_pio_rx(bcm->current_core->pio->queue3); + bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3); else - bcm43xx_dma_rx(bcm->current_core->dma->rx_ring1); + bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring1); activity = 1; } bcmirq_handled(BCM43xx_IRQ_RX); @@ -1911,7 +1914,7 @@ static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force) static int bcm43xx_request_firmware(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u8 rev = bcm->current_core->rev; int err = 0; int nr; @@ -2349,6 +2352,8 @@ static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm) */ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) { + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); int err; int iw_mode = bcm->ieee->iw_mode; int tmp; @@ -2388,13 +2393,13 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) goto err_radio_off; /* Select initial Interference Mitigation. */ - tmp = bcm->current_core->radio->interfmode; - bcm->current_core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; + tmp = radio->interfmode; + radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; bcm43xx_radio_set_interference_mitigation(bcm, tmp); bcm43xx_phy_set_antenna_diversity(bcm); bcm43xx_radio_set_txantenna(bcm, BCM43xx_RADIO_TXANTENNA_DEFAULT); - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) { + if (phy->type == BCM43xx_PHYTYPE_B) { value16 = bcm43xx_read16(bcm, 0x005E); value16 |= 0x0004; bcm43xx_write16(bcm, 0x005E, value16); @@ -2512,6 +2517,32 @@ error: return -ENODEV; } +void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) +{ + /* Initialize a "phyinfo" structure. The structure is already + * zeroed out. + */ + phy->antenna_diversity = 0xFFFF; + phy->savedpctlreg = 0xFFFF; + phy->minlowsig[0] = 0xFFFF; + phy->minlowsig[1] = 0xFFFF; + spin_lock_init(&phy->lock); +} + +void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio) +{ + /* Initialize a "radioinfo" structure. The structure is already + * zeroed out. + */ + radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; + radio->channel = 0xFF; + radio->initial_channel = 0xFF; + radio->lofcal = 0xFFFF; + radio->initval = 0xFFFF; + radio->nrssi[0] = -1000; + radio->nrssi[1] = -1000; +} + static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) { int err, i; @@ -2523,15 +2554,14 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) memset(&bcm->core_chipcommon, 0, sizeof(struct bcm43xx_coreinfo)); memset(&bcm->core_pci, 0, sizeof(struct bcm43xx_coreinfo)); - memset(&bcm->core_v90, 0, sizeof(struct bcm43xx_coreinfo)); - memset(&bcm->core_pcmcia, 0, sizeof(struct bcm43xx_coreinfo)); memset(&bcm->core_80211, 0, sizeof(struct bcm43xx_coreinfo) * BCM43xx_MAX_80211_CORES); - - memset(&bcm->phy, 0, sizeof(struct bcm43xx_phyinfo) - * BCM43xx_MAX_80211_CORES); - memset(&bcm->radio, 0, sizeof(struct bcm43xx_radioinfo) - * BCM43xx_MAX_80211_CORES); + memset(&bcm->core_80211_ext, 0, sizeof(struct bcm43xx_coreinfo_80211) + * BCM43xx_MAX_80211_CORES); + bcm->current_80211_core_idx = -1; + bcm->nr_80211_available = 0; + bcm->current_core = NULL; + bcm->active_80211_core = NULL; /* map core 0 */ err = _switch_core(bcm, 0); @@ -2549,7 +2579,7 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) if (core_id == BCM43xx_COREID_CHIPCOMMON) { chip_id_32 = bcm43xx_read32(bcm, 0); chip_id_16 = chip_id_32 & 0xFFFF; - bcm->core_chipcommon.flags |= BCM43xx_COREFLAG_AVAILABLE; + bcm->core_chipcommon.available = 1; bcm->core_chipcommon.id = core_id; bcm->core_chipcommon.rev = core_rev; bcm->core_chipcommon.index = 0; @@ -2618,18 +2648,19 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n", bcm->chip_id, bcm->chip_rev); dprintk(KERN_INFO PFX "Number of cores: %d\n", core_count); - if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE) { + if (bcm->core_chipcommon.available) { dprintk(KERN_INFO PFX "Core 0: ID 0x%x, rev 0x%x, vendor 0x%x, %s\n", core_id, core_rev, core_vendor, bcm43xx_core_enabled(bcm) ? "enabled" : "disabled"); } - if (bcm->core_chipcommon.flags & BCM43xx_COREFLAG_AVAILABLE) + if (bcm->core_chipcommon.available) current_core = 1; else current_core = 0; for ( ; current_core < core_count; current_core++) { struct bcm43xx_coreinfo *core; + struct bcm43xx_coreinfo_80211 *ext_80211; err = _switch_core(bcm, current_core); if (err) @@ -2651,36 +2682,16 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) switch (core_id) { case BCM43xx_COREID_PCI: core = &bcm->core_pci; - if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { + if (core->available) { printk(KERN_WARNING PFX "Multiple PCI cores found.\n"); continue; } break; - case BCM43xx_COREID_V90: - core = &bcm->core_v90; - if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { - printk(KERN_WARNING PFX "Multiple V90 cores found.\n"); - continue; - } - break; - case BCM43xx_COREID_PCMCIA: - core = &bcm->core_pcmcia; - if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { - printk(KERN_WARNING PFX "Multiple PCMCIA cores found.\n"); - continue; - } - break; - case BCM43xx_COREID_ETHERNET: - core = &bcm->core_ethernet; - if (core->flags & BCM43xx_COREFLAG_AVAILABLE) { - printk(KERN_WARNING PFX "Multiple Ethernet cores found.\n"); - continue; - } - break; case BCM43xx_COREID_80211: for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { core = &(bcm->core_80211[i]); - if (!(core->flags & BCM43xx_COREFLAG_AVAILABLE)) + ext_80211 = &(bcm->core_80211_ext[i]); + if (!core->available) break; core = NULL; } @@ -2715,40 +2726,23 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) err = -ENODEV; goto out; } - core->phy = &bcm->phy[i]; - core->phy->antenna_diversity = 0xffff; - core->phy->savedpctlreg = 0xFFFF; - core->phy->minlowsig[0] = 0xFFFF; - core->phy->minlowsig[1] = 0xFFFF; - core->phy->minlowsigpos[0] = 0; - core->phy->minlowsigpos[1] = 0; - spin_lock_init(&core->phy->lock); - core->radio = &bcm->radio[i]; - core->radio->interfmode = BCM43xx_RADIO_INTERFMODE_NONE; - core->radio->channel = 0xFF; - core->radio->initial_channel = 0xFF; - core->radio->lofcal = 0xFFFF; - core->radio->initval = 0xFFFF; - core->radio->nrssi[0] = -1000; - core->radio->nrssi[1] = -1000; - core->dma = &bcm->dma[i]; - core->pio = &bcm->pio[i]; + bcm->nr_80211_available++; + bcm43xx_init_struct_phyinfo(&ext_80211->phy); + bcm43xx_init_struct_radioinfo(&ext_80211->radio); break; case BCM43xx_COREID_CHIPCOMMON: printk(KERN_WARNING PFX "Multiple CHIPCOMMON cores found.\n"); break; - default: - printk(KERN_WARNING PFX "Unknown core found (ID 0x%x)\n", core_id); } if (core) { - core->flags |= BCM43xx_COREFLAG_AVAILABLE; + core->available = 1; core->id = core_id; core->rev = core_rev; core->index = current_core; } } - if (!(bcm->core_80211[0].flags & BCM43xx_COREFLAG_AVAILABLE)) { + if (!bcm->core_80211[0].available) { printk(KERN_ERR PFX "Error: No 80211 core found!\n"); err = -ENODEV; goto out; @@ -2802,7 +2796,7 @@ static void bcm43xx_rate_memory_write(struct bcm43xx_private *bcm, static void bcm43xx_rate_memory_init(struct bcm43xx_private *bcm) { - switch (bcm->current_core->phy->type) { + switch (bcm43xx_current_phy(bcm)->type) { case BCM43xx_PHYTYPE_A: case BCM43xx_PHYTYPE_G: bcm43xx_rate_memory_write(bcm, IEEE80211_OFDM_RATE_6MB, 1); @@ -2829,12 +2823,14 @@ static void bcm43xx_wireless_core_cleanup(struct bcm43xx_private *bcm) bcm43xx_pio_free(bcm); bcm43xx_dma_free(bcm); - bcm->current_core->flags &= ~ BCM43xx_COREFLAG_INITIALIZED; + bcm->current_core->initialized = 0; } /* http://bcm-specs.sipsolutions.net/80211Init */ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u32 ucodeflags; int err; u32 sbimconfiglow; @@ -2867,16 +2863,15 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) /* HW decryption needs to be set now */ ucodeflags |= 0x40000000; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + if (phy->type == BCM43xx_PHYTYPE_G) { ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; - if (bcm->current_core->phy->rev == 1) + if (phy->rev == 1) ucodeflags |= BCM43xx_UCODEFLAG_UNKGPHY; if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) ucodeflags |= BCM43xx_UCODEFLAG_UNKPACTRL; - } else if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) { + } else if (phy->type == BCM43xx_PHYTYPE_B) { ucodeflags |= BCM43xx_UCODEFLAG_UNKBGPHY; - if ((bcm->current_core->phy->rev >= 2) && - (bcm->current_core->radio->version == 0x2050)) + if (phy->rev >= 2 && radio->version == 0x2050) ucodeflags &= ~BCM43xx_UCODEFLAG_UNKGPHY; } @@ -2901,7 +2896,7 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) bcm43xx_rate_memory_init(bcm); /* Minimum Contention Window */ - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B) + if (phy->type == BCM43xx_PHYTYPE_B) bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000001f); else bcm43xx_shm_write32(bcm, BCM43xx_SHM_WIRELESS, 0x0003, 0x0000000f); @@ -2927,7 +2922,7 @@ static int bcm43xx_wireless_core_init(struct bcm43xx_private *bcm) bcm43xx_mac_enable(bcm); bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate); - bcm->current_core->flags |= BCM43xx_COREFLAG_INITIALIZED; + bcm->current_core->initialized = 1; out: return err; @@ -3048,7 +3043,7 @@ static void bcm43xx_softmac_init(struct bcm43xx_private *bcm) static void bcm43xx_periodic_every120sec(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); if (phy->type != BCM43xx_PHYTYPE_G || phy->rev < 2) return; @@ -3076,8 +3071,8 @@ static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm) static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); if (phy->type == BCM43xx_PHYTYPE_G) { //TODO: update_aci_moving_average @@ -3170,9 +3165,9 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) bcm43xx_unlock(bcm, flags); for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { - if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_AVAILABLE)) + if (!bcm->core_80211[i].available) continue; - if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED)) + if (!bcm->core_80211[i].initialized) continue; err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); @@ -3190,7 +3185,6 @@ static void bcm43xx_free_board(struct bcm43xx_private *bcm) static int bcm43xx_init_board(struct bcm43xx_private *bcm) { int i, err; - int num_80211_cores; int connect_phy; unsigned long flags; @@ -3212,8 +3206,7 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) goto err_crystal_off; tasklet_enable(&bcm->isr_tasklet); - num_80211_cores = bcm43xx_num_80211_cores(bcm); - for (i = 0; i < num_80211_cores; i++) { + for (i = 0; i < bcm->nr_80211_available; i++) { err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); assert(err != -ENODEV); if (err) @@ -3223,8 +3216,8 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) * Connect PHY only on the first core. */ if (!bcm43xx_core_enabled(bcm)) { - if (num_80211_cores == 1) { - connect_phy = bcm->current_core->phy->connected; + if (bcm->nr_80211_available == 1) { + connect_phy = bcm43xx_current_phy(bcm)->connected; } else { if (i == 0) connect_phy = 1; @@ -3248,7 +3241,7 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) } } bcm->active_80211_core = &bcm->core_80211[0]; - if (num_80211_cores >= 2) { + if (bcm->nr_80211_available >= 2) { bcm43xx_switch_core(bcm, &bcm->core_80211[0]); bcm43xx_mac_enable(bcm); } @@ -3260,9 +3253,9 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm) bcm43xx_pctl_set_clock(bcm, BCM43xx_PCTL_CLK_DYNAMIC); - if (bcm->current_core->radio->initial_channel != 0xFF) { + if (bcm43xx_current_radio(bcm)->initial_channel != 0xFF) { bcm43xx_mac_suspend(bcm); - bcm43xx_radio_selectchannel(bcm, bcm->current_core->radio->initial_channel, 0); + bcm43xx_radio_selectchannel(bcm, bcm43xx_current_radio(bcm)->initial_channel, 0); bcm43xx_mac_enable(bcm); } @@ -3282,8 +3275,8 @@ out: err_80211_unwind: tasklet_disable(&bcm->isr_tasklet); /* unwind all 80211 initialization */ - for (i = 0; i < num_80211_cores; i++) { - if (!(bcm->core_80211[i].flags & BCM43xx_COREFLAG_INITIALIZED)) + for (i = 0; i < bcm->nr_80211_available; i++) { + if (!bcm->core_80211[i].initialized) continue; bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); bcm43xx_wireless_core_cleanup(bcm); @@ -3307,15 +3300,15 @@ static void bcm43xx_detach_board(struct bcm43xx_private *bcm) /* Free allocated structures/fields */ for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { - kfree(bcm->phy[i]._lo_pairs); - if (bcm->phy[i].dyn_tssi_tbl) - kfree(bcm->phy[i].tssi2dbm); + kfree(bcm->core_80211_ext[i].phy._lo_pairs); + if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl) + kfree(bcm->core_80211_ext[i].phy.tssi2dbm); } } static int bcm43xx_read_phyinfo(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 value; u8 phy_version; u8 phy_type; @@ -3393,7 +3386,6 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) int i; void __iomem *ioaddr; unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; - int num_80211_cores; u32 coremask; err = pci_enable_device(pci_dev); @@ -3467,11 +3459,9 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) if (err) goto err_chipset_detach; - num_80211_cores = bcm43xx_num_80211_cores(bcm); - /* Attach all IO cores to the backplane. */ coremask = 0; - for (i = 0; i < num_80211_cores; i++) + for (i = 0; i < bcm->nr_80211_available; i++) coremask |= (1 << bcm->core_80211[i].index); //FIXME: Also attach some non80211 cores? err = bcm43xx_setup_backplane_pci_connection(bcm, coremask); @@ -3487,7 +3477,7 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) if (err) goto err_chipset_detach; - for (i = 0; i < num_80211_cores; i++) { + for (i = 0; i < bcm->nr_80211_available; i++) { err = bcm43xx_switch_core(bcm, &bcm->core_80211[i]); assert(err != -ENODEV); if (err) @@ -3519,7 +3509,7 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) bcm43xx_pctl_set_crystal(bcm, 0); /* Set the MAC address in the networking subsystem */ - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6); else memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6); @@ -3535,9 +3525,9 @@ out: err_80211_unwind: for (i = 0; i < BCM43xx_MAX_80211_CORES; i++) { - kfree(bcm->phy[i]._lo_pairs); - if (bcm->phy[i].dyn_tssi_tbl) - kfree(bcm->phy[i].tssi2dbm); + kfree(bcm->core_80211_ext[i].phy._lo_pairs); + if (bcm->core_80211_ext[i].phy.dyn_tssi_tbl) + kfree(bcm->core_80211_ext[i].phy.tssi2dbm); } err_chipset_detach: bcm43xx_chipset_detach(bcm); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.h b/drivers/net/wireless/bcm43xx/bcm43xx_main.h index 086136c3d01..eca79a38594 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.h @@ -80,7 +80,7 @@ static inline u8 bcm43xx_freq_to_channel(struct bcm43xx_private *bcm, int freq) { - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) return bcm43xx_freq_to_channel_a(freq); return bcm43xx_freq_to_channel_bg(freq); } @@ -107,7 +107,7 @@ static inline int bcm43xx_channel_to_freq(struct bcm43xx_private *bcm, u8 channel) { - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) return bcm43xx_channel_to_freq_a(channel); return bcm43xx_channel_to_freq_bg(channel); } @@ -129,7 +129,7 @@ static inline int bcm43xx_is_valid_channel(struct bcm43xx_private *bcm, u8 channel) { - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A) return bcm43xx_is_valid_channel_a(channel); return bcm43xx_is_valid_channel_bg(channel); } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index dbbef6ccd15..1ce9a459990 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -83,7 +83,7 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm); void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); assert(irqs_disabled()); if (bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) == 0x00000000) { @@ -102,7 +102,7 @@ void bcm43xx_raw_phy_lock(struct bcm43xx_private *bcm) void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); assert(irqs_disabled()); if (bcm->current_core->rev < 3) { @@ -132,7 +132,7 @@ void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val) void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); unsigned long flags; bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Dummy read. */ @@ -158,39 +158,32 @@ void bcm43xx_phy_calibrate(struct bcm43xx_private *bcm) */ int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u32 flags; - if (bcm->current_core->rev < 5) { - if (connect) { - bcm->current_core->phy->connected = 1; - dprintk(KERN_INFO PFX "PHY connected\n"); - } else { - bcm->current_core->phy->connected = 0; - dprintk(KERN_INFO PFX "PHY disconnected\n"); - } - return 0; - } - + if (bcm->current_core->rev < 5) + goto out; + flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); if (connect) { if (!(flags & 0x00010000)) return -ENODEV; - bcm->current_core->phy->connected = 1; - flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); flags |= (0x800 << 18); bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); - dprintk(KERN_INFO PFX "PHY connected\n"); } else { if (!(flags & 0x00020000)) return -ENODEV; - bcm->current_core->phy->connected = 0; - flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); flags &= ~(0x800 << 18); bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); - dprintk(KERN_INFO PFX "PHY disconnected\n"); } +out: + phy->connected = connect; + if (connect) + dprintk(KERN_INFO PFX "PHY connected\n"); + else + dprintk(KERN_INFO PFX "PHY disconnected\n"); return 0; } @@ -200,8 +193,8 @@ int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect) */ static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 saved_batt = 0, saved_ratt = 0, saved_txctl1 = 0; int must_reset_txpower = 0; @@ -250,7 +243,7 @@ static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm) static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 offset = 0x0000; if (phy->rev == 1) @@ -326,7 +319,7 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 i; assert(phy->type == BCM43xx_PHYTYPE_G); @@ -420,7 +413,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) /* Initialize the noisescaletable for APHY */ static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); int i; bcm43xx_phy_write(bcm, BCM43xx_PHY_ILT_A_CTRL, 0x1400); @@ -448,10 +441,11 @@ static void bcm43xx_phy_init_noisescaletbl(struct bcm43xx_private *bcm) static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 i; - assert(bcm->current_core->phy->type == BCM43xx_PHYTYPE_A); - switch (bcm->current_core->phy->rev) { + assert(phy->type == BCM43xx_PHYTYPE_A); + switch (phy->rev) { case 2: bcm43xx_phy_write(bcm, 0x008E, 0x3800); bcm43xx_phy_write(bcm, 0x0035, 0x03FF); @@ -563,7 +557,8 @@ static void bcm43xx_phy_setupa(struct bcm43xx_private *bcm) /* Initialize APHY. This is also called for the GPHY in some cases. */ static void bcm43xx_phy_inita(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 tval; if (phy->type == BCM43xx_PHYTYPE_A) { @@ -586,11 +581,11 @@ static void bcm43xx_phy_inita(struct bcm43xx_private *bcm) if ((bcm->board_vendor == PCI_VENDOR_ID_BROADCOM) && ((bcm->board_type == 0x0416) || (bcm->board_type == 0x040A))) { - if (bcm->current_core->radio->lofcal == 0xFFFF) { + if (radio->lofcal == 0xFFFF) { TODO();//TODO: LOF Cal bcm43xx_radio_set_tx_iq(bcm); } else - bcm43xx_radio_write16(bcm, 0x001E, bcm->current_core->radio->lofcal); + bcm43xx_radio_write16(bcm, 0x001E, radio->lofcal); } bcm43xx_phy_write(bcm, 0x007A, 0xF111); @@ -620,7 +615,7 @@ static void bcm43xx_phy_inita(struct bcm43xx_private *bcm) static void bcm43xx_phy_initb2(struct bcm43xx_private *bcm) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 offset, val; bcm43xx_write16(bcm, 0x03EC, 0x3F22); @@ -671,7 +666,7 @@ static void bcm43xx_phy_initb2(struct bcm43xx_private *bcm) static void bcm43xx_phy_initb4(struct bcm43xx_private *bcm) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 offset, val; bcm43xx_write16(bcm, 0x03EC, 0x3F22); @@ -729,8 +724,8 @@ static void bcm43xx_phy_initb4(struct bcm43xx_private *bcm) static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 offset; if (phy->version == 1 && @@ -835,8 +830,8 @@ static void bcm43xx_phy_initb5(struct bcm43xx_private *bcm) static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 offset, val; bcm43xx_phy_write(bcm, 0x003E, 0x817A); @@ -946,9 +941,9 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) udelay(40); bcm43xx_radio_write16(bcm, 0x007C, (bcm43xx_radio_read16(bcm, 0x007C) | 0x0002)); bcm43xx_radio_write16(bcm, 0x0050, 0x0020); - if ((bcm->current_core->radio->manufact == 0x17F) && - (bcm->current_core->radio->version == 0x2050) && - (bcm->current_core->radio->revision <= 2)) { + if (radio->manufact == 0x17F && + radio->version == 0x2050 && + radio->revision <= 2) { bcm43xx_radio_write16(bcm, 0x0050, 0x0020); bcm43xx_radio_write16(bcm, 0x005A, 0x0070); bcm43xx_radio_write16(bcm, 0x005B, 0x007B); @@ -1001,8 +996,8 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 tmp; if (phy->rev == 1) @@ -1096,8 +1091,8 @@ static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm) void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 regstack[12] = { 0 }; u16 mls; u16 fval; @@ -1190,7 +1185,9 @@ void bcm43xx_phy_lo_b_measure(struct bcm43xx_private *bcm) static inline u16 bcm43xx_phy_lo_g_deviation_subval(struct bcm43xx_private *bcm, u16 control) { - if (bcm->current_core->phy->connected) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + + if (phy->connected) { bcm43xx_phy_write(bcm, 0x15, 0xE300); control <<= 8; bcm43xx_phy_write(bcm, 0x0812, control | 0x00B0); @@ -1242,7 +1239,7 @@ void bcm43xx_lo_write(struct bcm43xx_private *bcm, "WARNING: Writing invalid LOpair " "(low: %d, high: %d, index: %lu)\n", pair->low, pair->high, - (unsigned long)(pair - bcm->current_core->phy->_lo_pairs)); + (unsigned long)(pair - bcm43xx_current_phy(bcm)->_lo_pairs)); dump_stack(); } #endif @@ -1257,7 +1254,7 @@ struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm, u16 tx) { static const u8 dict[10] = { 11, 10, 11, 12, 13, 12, 13, 12, 13, 12 }; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); if (baseband_attenuation > 6) baseband_attenuation = 6; @@ -1275,10 +1272,12 @@ struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm, static inline struct bcm43xx_lopair * bcm43xx_current_lopair(struct bcm43xx_private *bcm) { + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + return bcm43xx_find_lopair(bcm, - bcm->current_core->radio->txpower[0], - bcm->current_core->radio->txpower[1], - bcm->current_core->radio->txpower[2]); + radio->txpower[0], + radio->txpower[1], + radio->txpower[2]); } /* Adjust B/G LO */ @@ -1294,9 +1293,9 @@ void bcm43xx_phy_lo_adjust(struct bcm43xx_private *bcm, int fixed) bcm43xx_lo_write(bcm, pair); } -static inline -void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm) +static void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm) { + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 txctl2 = 0, i; u32 smallest, tmp; @@ -1312,7 +1311,7 @@ void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm) txctl2 = i; } } - bcm->current_core->radio->txpower[3] = txctl2; + radio->txpower[3] = txctl2; } static @@ -1402,16 +1401,17 @@ void bcm43xx_phy_lo_g_state(struct bcm43xx_private *bcm, void bcm43xx_phy_set_baseband_attenuation(struct bcm43xx_private *bcm, u16 baseband_attenuation) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 value; - if (bcm->current_core->phy->version == 0) { + if (phy->version == 0) { value = (bcm43xx_read16(bcm, 0x03E6) & 0xFFF0); value |= (baseband_attenuation & 0x000F); bcm43xx_write16(bcm, 0x03E6, value); return; } - if (bcm->current_core->phy->version > 1) { + if (phy->version > 1) { value = bcm43xx_phy_read(bcm, 0x0060) & ~0x003C; value |= (baseband_attenuation << 2) & 0x003C; } else { @@ -1426,8 +1426,8 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) { static const u8 pairorder[10] = { 3, 1, 5, 7, 9, 2, 0, 4, 6, 8 }; const int is_initializing = bcm43xx_is_initializing(bcm); - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 h, i, oldi = 0, j; struct bcm43xx_lopair control; struct bcm43xx_lopair *tmp_control; @@ -1653,7 +1653,7 @@ void bcm43xx_phy_lo_mark_current_used(struct bcm43xx_private *bcm) void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_lopair *pair; int i; @@ -1668,7 +1668,7 @@ void bcm43xx_phy_lo_mark_all_unused(struct bcm43xx_private *bcm) */ static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); s8 dbm = 0; s32 tmp; @@ -1698,8 +1698,8 @@ static s8 bcm43xx_phy_estimate_power_out(struct bcm43xx_private *bcm, s8 tssi) /* http://bcm-specs.sipsolutions.net/RecalculateTransmissionPower */ void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); if (phy->savedpctlreg == 0xFFFF) return; @@ -1880,8 +1880,8 @@ s8 bcm43xx_tssi2dbm_entry(s8 entry [], u8 index, s16 pab0, s16 pab1, s16 pab2) /* http://bcm-specs.sipsolutions.net/TSSI_to_DBM_Table */ int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); s16 pab0, pab1, pab2; u8 idx; s8 *dyn_tssi2dbm; @@ -1958,7 +1958,7 @@ int bcm43xx_phy_init_tssi2dbm_table(struct bcm43xx_private *bcm) int bcm43xx_phy_init(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); int err = -ENODEV; unsigned long flags; @@ -2008,7 +2008,7 @@ int bcm43xx_phy_init(struct bcm43xx_private *bcm) void bcm43xx_phy_set_antenna_diversity(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 antennadiv; u16 offset; u16 value; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 26dc6047d45..7bddae910de 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -146,7 +146,7 @@ struct bcm43xx_pioqueue * parse_cookie(struct bcm43xx_private *bcm, u16 cookie, struct bcm43xx_pio_txpacket **packet) { - struct bcm43xx_pio *pio = bcm->current_core->pio; + struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); struct bcm43xx_pioqueue *queue = NULL; int packetindex; @@ -377,7 +377,7 @@ static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) void bcm43xx_pio_free(struct bcm43xx_private *bcm) { - struct bcm43xx_pio *pio = bcm->current_core->pio; + struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); bcm43xx_destroy_pioqueue(pio->queue3); pio->queue3 = NULL; @@ -391,7 +391,7 @@ void bcm43xx_pio_free(struct bcm43xx_private *bcm) int bcm43xx_pio_init(struct bcm43xx_private *bcm) { - struct bcm43xx_pio *pio = bcm->current_core->pio; + struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); struct bcm43xx_pioqueue *queue; int err = -ENOMEM; @@ -438,7 +438,7 @@ err_destroy0: int bcm43xx_pio_tx(struct bcm43xx_private *bcm, struct ieee80211_txb *txb) { - struct bcm43xx_pioqueue *queue = bcm->current_core->pio->queue1; + struct bcm43xx_pioqueue *queue = bcm43xx_current_pio(bcm)->queue1; struct bcm43xx_pio_txpacket *packet; u16 tmp; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 4d3b0e85876..07a6169a0b3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -114,8 +114,8 @@ void bcm43xx_radio_unlock(struct bcm43xx_private *bcm) u16 bcm43xx_radio_read16(struct bcm43xx_private *bcm, u16 offset) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); switch (phy->type) { case BCM43xx_PHYTYPE_A: @@ -151,7 +151,7 @@ void bcm43xx_radio_write16(struct bcm43xx_private *bcm, u16 offset, u16 val) static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm, s16 first, s16 second, s16 third) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 i; u16 start = 0x08, end = 0x18; u16 offset = 0x0400; @@ -183,7 +183,7 @@ static void bcm43xx_set_all_gains(struct bcm43xx_private *bcm, static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 i, tmp; u16 offset = 0x0400; u16 start = 0x0008, end = 0x0018; @@ -217,7 +217,7 @@ static void bcm43xx_set_original_gains(struct bcm43xx_private *bcm) /* Synthetic PU workaround */ static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); if (radio->version != 0x2050 || radio->revision >= 6) { /* We do not need the workaround. */ @@ -238,7 +238,7 @@ static void bcm43xx_synth_pu_workaround(struct bcm43xx_private *bcm, u8 channel) u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u8 ret = 0; u16 saved, rssi, temp; int i, j = 0; @@ -269,8 +269,8 @@ u8 bcm43xx_radio_aci_detect(struct bcm43xx_private *bcm, u8 channel) u8 bcm43xx_radio_aci_scan(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u8 ret[13]; unsigned int channel = radio->channel; unsigned int i, j, start, end; @@ -351,22 +351,23 @@ void bcm43xx_nrssi_hw_update(struct bcm43xx_private *bcm, u16 val) /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ void bcm43xx_nrssi_mem_update(struct bcm43xx_private *bcm) { + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); s16 i, delta; s32 tmp; - delta = 0x1F - bcm->current_core->radio->nrssi[0]; + delta = 0x1F - radio->nrssi[0]; for (i = 0; i < 64; i++) { - tmp = (i - delta) * bcm->current_core->radio->nrssislope; + tmp = (i - delta) * radio->nrssislope; tmp /= 0x10000; tmp += 0x3A; tmp = limit_value(tmp, 0, 0x3F); - bcm->current_core->radio->nrssi_lt[i] = tmp; + radio->nrssi_lt[i] = tmp; } } static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u16 backup[20] = { 0 }; s16 v47F; u16 i; @@ -531,8 +532,8 @@ static void bcm43xx_calc_nrssi_offset(struct bcm43xx_private *bcm) void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 backup[18] = { 0 }; u16 tmp; s16 nrssi0, nrssi1; @@ -779,8 +780,8 @@ void bcm43xx_calc_nrssi_slope(struct bcm43xx_private *bcm) void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); s16 threshold; s32 a, b; int tmp; @@ -804,7 +805,7 @@ void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) radiotype = 1; if (radiotype == 1) { - threshold = bcm->current_core->radio->nrssi[1] - 5; + threshold = radio->nrssi[1] - 5; } else { threshold = 40 * radio->nrssi[0]; threshold += 33 * (radio->nrssi[1] - radio->nrssi[0]); @@ -901,8 +902,8 @@ static void bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm, int mode) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); int i = 0; u16 *stack = radio->interfstack; u16 tmp, flipped; @@ -1052,8 +1053,8 @@ static void bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, int mode) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); int i = 0; u16 *stack = radio->interfstack; u16 tmp, flipped; @@ -1142,8 +1143,8 @@ bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, int mode) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); int currentmode; if ((phy->type != BCM43xx_PHYTYPE_G) || @@ -1199,8 +1200,8 @@ u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm) u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 backup[19] = { 0 }; u16 ret; u16 i, j; @@ -1444,7 +1445,7 @@ int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel, int synthetic_pu_workaround) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 r8, tmp; u16 freq; @@ -1628,6 +1629,7 @@ static u16 bcm43xx_get_txgain_dac(u16 txpower) void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower) { + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 pamp, base, dac, ilt; txpower = limit_value(txpower, 0, 63); @@ -1650,7 +1652,7 @@ void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower) bcm43xx_ilt_write(bcm, 0x3001, dac); - bcm->current_core->radio->txpower[0] = txpower; + radio->txpower[0] = txpower; TODO(); //TODO: FuncPlaceholder (Adjust BB loft cancel) @@ -1660,8 +1662,8 @@ void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, u16 baseband_attenuation, u16 radio_attenuation, u16 txpower) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); if (baseband_attenuation == 0xFFFF) baseband_attenuation = radio->txpower[0]; @@ -1698,8 +1700,8 @@ void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); int err; if (radio->enabled) @@ -1730,8 +1732,8 @@ void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm) void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); if (phy->type == BCM43xx_PHYTYPE_A) { bcm43xx_radio_write16(bcm, 0x0004, 0x00FF); @@ -1750,7 +1752,9 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm) void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm) { - switch (bcm->current_core->phy->type) { + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + + switch (phy->type) { case BCM43xx_PHYTYPE_A: bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0068, 0x7F7F); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x006a, 0x7F7F); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c index 713ec601c34..35c3c9704c3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c @@ -150,7 +150,7 @@ static ssize_t bcm43xx_attr_interfmode_show(struct device *dev, bcm43xx_lock(bcm, flags); assert(bcm->initialized); - switch (bcm->current_core->radio->interfmode) { + switch (bcm43xx_current_radio(bcm)->interfmode) { case BCM43xx_RADIO_INTERFMODE_NONE: count = snprintf(buf, PAGE_SIZE, "0 (No Interference Mitigation)\n"); break; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 208193851e8..651ba605495 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -56,15 +56,14 @@ static int bcm43xx_wx_get_name(struct net_device *net_dev, { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); unsigned long flags; - int i, nr_80211; + int i; struct bcm43xx_phyinfo *phy; char suffix[7] = { 0 }; int have_a = 0, have_b = 0, have_g = 0; bcm43xx_lock(bcm, flags); - nr_80211 = bcm43xx_num_80211_cores(bcm); - for (i = 0; i < nr_80211; i++) { - phy = bcm->phy + i; + for (i = 0; i < bcm->nr_80211_available; i++) { + phy = &(bcm->core_80211_ext[i].phy); switch (phy->type) { case BCM43xx_PHYTYPE_A: have_a = 1; @@ -129,7 +128,7 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, err = bcm43xx_radio_selectchannel(bcm, channel, 0); bcm43xx_mac_enable(bcm); } else { - bcm->current_core->radio->initial_channel = channel; + bcm43xx_current_radio(bcm)->initial_channel = channel; err = 0; } out_unlock: @@ -144,15 +143,17 @@ static int bcm43xx_wx_get_channelfreq(struct net_device *net_dev, char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct bcm43xx_radioinfo *radio; unsigned long flags; int err = -ENODEV; u16 channel; bcm43xx_lock(bcm, flags); - channel = bcm->current_core->radio->channel; + radio = bcm43xx_current_radio(bcm); + channel = radio->channel; if (channel == 0xFF) { assert(!bcm->initialized); - channel = bcm->current_core->radio->initial_channel; + channel = radio->initial_channel; if (channel == 0xFF) goto out_unlock; } @@ -232,6 +233,7 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, const struct ieee80211_geo *geo; unsigned long flags; int i, j; + struct bcm43xx_phyinfo *phy; data->data.length = sizeof(*range); memset(range, 0, sizeof(*range)); @@ -270,11 +272,12 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, IW_ENC_CAPA_CIPHER_CCMP; bcm43xx_lock(bcm, flags); + phy = bcm43xx_current_phy(bcm); range->num_bitrates = 0; i = 0; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A || - bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + if (phy->type == BCM43xx_PHYTYPE_A || + phy->type == BCM43xx_PHYTYPE_G) { range->num_bitrates = 8; range->bitrate[i++] = IEEE80211_OFDM_RATE_6MB; range->bitrate[i++] = IEEE80211_OFDM_RATE_9MB; @@ -285,8 +288,8 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, range->bitrate[i++] = IEEE80211_OFDM_RATE_48MB; range->bitrate[i++] = IEEE80211_OFDM_RATE_54MB; } - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_B || - bcm->current_core->phy->type == BCM43xx_PHYTYPE_G) { + if (phy->type == BCM43xx_PHYTYPE_B || + phy->type == BCM43xx_PHYTYPE_G) { range->num_bitrates += 4; range->bitrate[i++] = IEEE80211_CCK_RATE_1MB; range->bitrate[i++] = IEEE80211_CCK_RATE_2MB; @@ -461,8 +464,8 @@ static int bcm43xx_wx_set_xmitpower(struct net_device *net_dev, bcm43xx_lock_mmio(bcm, flags); if (!bcm->initialized) goto out_unlock; - radio = bcm->current_core->radio; - phy = bcm->current_core->phy; + radio = bcm43xx_current_radio(bcm); + phy = bcm43xx_current_phy(bcm); if (data->txpower.disabled != (!(radio->enabled))) { if (data->txpower.disabled) bcm43xx_radio_turn_off(bcm); @@ -500,7 +503,7 @@ static int bcm43xx_wx_get_xmitpower(struct net_device *net_dev, bcm43xx_lock(bcm, flags); if (!bcm->initialized) goto out_unlock; - radio = bcm->current_core->radio; + radio = bcm43xx_current_radio(bcm); /* desired dBm value is in Q5.2 */ data->txpower.value = radio->txpower_desired >> 2; data->txpower.fixed = 1; @@ -645,7 +648,7 @@ static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, "not supported while the interface is down.\n"); err = -ENODEV; } else - bcm->current_core->radio->interfmode = mode; + bcm43xx_current_radio(bcm)->interfmode = mode; } bcm43xx_unlock_mmio(bcm, flags); @@ -662,7 +665,7 @@ static int bcm43xx_wx_get_interfmode(struct net_device *net_dev, int mode; bcm43xx_lock(bcm, flags); - mode = bcm->current_core->radio->interfmode; + mode = bcm43xx_current_radio(bcm)->interfmode; bcm43xx_unlock(bcm, flags); switch (mode) { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c index 5ee572e79f6..c4809da8e9c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c @@ -284,7 +284,7 @@ void bcm43xx_generate_txhdr(struct bcm43xx_private *bcm, const int is_first_fragment, const u16 cookie) { - const struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + const struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); const struct ieee80211_hdr_4addr *wireless_header = (const struct ieee80211_hdr_4addr *)fragment_data; const struct ieee80211_security *secinfo = &bcm->ieee->sec; u8 bitrate; @@ -382,8 +382,8 @@ static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, u8 in_rssi, int ofdm, int adjust_2053, int adjust_2050) { - struct bcm43xx_radioinfo *radio = bcm->current_core->radio; - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); s32 tmp; switch (radio->version) { @@ -442,7 +442,7 @@ static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, u8 in_rssi) { - struct bcm43xx_phyinfo *phy = bcm->current_core->phy; + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); s8 ret; if (phy->type == BCM43xx_PHYTYPE_A) { @@ -458,6 +458,8 @@ int bcm43xx_rx(struct bcm43xx_private *bcm, struct sk_buff *skb, struct bcm43xx_rxhdr *rxhdr) { + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_plcp_hdr4 *plcp; struct ieee80211_rx_stats stats; struct ieee80211_hdr_4addr *wlhdr; @@ -494,13 +496,13 @@ int bcm43xx_rx(struct bcm43xx_private *bcm, else stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp); //printk("RX ofdm %d, rate == %u\n", is_ofdm, stats.rate); - stats.received_channel = bcm->current_core->radio->channel; + stats.received_channel = radio->channel; //TODO stats.control = stats.mask = IEEE80211_STATMASK_SIGNAL | //TODO IEEE80211_STATMASK_NOISE | IEEE80211_STATMASK_RATE | IEEE80211_STATMASK_RSSI; - if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A) + if (phy->type == BCM43xx_PHYTYPE_A) stats.freq = IEEE80211_52GHZ_BAND; else stats.freq = IEEE80211_24GHZ_BAND; -- cgit v1.2.3 From 49f29efa7f44a79b64c7882c68e171898d0495a0 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 14 Mar 2006 16:05:26 +0100 Subject: [PATCH] bcm43xx: Fix crash on ifdown, by being careful in pio/dma freeing. This bug was caused by the packing of the bcm43xx_dma and bcm43xx_pio structures into a union. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 6 +++++- drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index 7ed368a587f..9c64438b767 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -531,7 +531,11 @@ static void bcm43xx_destroy_dmaring(struct bcm43xx_dmaring *ring) void bcm43xx_dma_free(struct bcm43xx_private *bcm) { - struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); + struct bcm43xx_dma *dma; + + if (bcm43xx_using_pio(bcm)) + return; + dma = bcm43xx_current_dma(bcm); bcm43xx_destroy_dmaring(dma->rx_ring1); dma->rx_ring1 = NULL; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 7bddae910de..5b6f0a84d01 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -377,7 +377,11 @@ static void bcm43xx_destroy_pioqueue(struct bcm43xx_pioqueue *queue) void bcm43xx_pio_free(struct bcm43xx_private *bcm) { - struct bcm43xx_pio *pio = bcm43xx_current_pio(bcm); + struct bcm43xx_pio *pio; + + if (!bcm43xx_using_pio(bcm)) + return; + pio = bcm43xx_current_pio(bcm); bcm43xx_destroy_pioqueue(pio->queue3); pio->queue3 = NULL; -- cgit v1.2.3 From 4cf6f03e067d6d416f5c9219471daf64703afae4 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 14 Mar 2006 18:23:43 +0100 Subject: [PATCH] bcm43xx: Remove the workaround in dummy_transmission, as it causes more trouble than it solves Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 88e9a125c2d..cc8efe74f53 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -996,13 +996,6 @@ void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm) 0x00000000, }; -/* FIXME: It seems like a dummy_transmission corrupts the DMA engines, - * once they are initialized. So avoid doing a dummy_transmission, - * if the DMA engines are running. - */ -if (bcm->initialized) -return; - switch (phy->type) { case BCM43xx_PHYTYPE_A: max_loop = 0x1E; -- cgit v1.2.3 From b3db5e553876c1743eefae5963aea431ec4d5ba6 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 15 Mar 2006 16:31:45 +0100 Subject: [PATCH] bcm43xx: Do boardflags workarounds for specific boards. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 4 ++++ drivers/net/wireless/bcm43xx/bcm43xx_main.c | 9 +++++++++ 2 files changed, 13 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index a358646ad3e..8820012b4b3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -120,6 +120,10 @@ #define BCM43xx_BFL_AFTERBURNER 0x0200 /* supports Afterburner mode */ #define BCM43xx_BFL_NOPCI 0x0400 /* leaves PCI floating */ #define BCM43xx_BFL_FEM 0x0800 /* supports the Front End Module */ +#define BCM43xx_BFL_EXTLNA 0x1000 /* has an external LNA */ +#define BCM43xx_BFL_HGPA 0x2000 /* had high gain PA */ +#define BCM43xx_BFL_BTCMOD 0x4000 /* BFL_BTCOEXIST is given in alternate GPIOs */ +#define BCM43xx_BFL_ALTIQ 0x8000 /* alternate I/Q settings */ /* GPIO register offset, in both ChipCommon and PCI core. */ #define BCM43xx_GPIO_CONTROL 0x6c diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index cc8efe74f53..e26507b11f0 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -910,6 +910,15 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm) if (value == 0xFFFF) value = 0x0000; bcm->sprom.boardflags = value; + /* boardflags workarounds */ + if (bcm->board_vendor == PCI_VENDOR_ID_DELL && + bcm->chip_id == 0x4301 && + bcm->board_revision == 0x74) + bcm->sprom.boardflags |= BCM43xx_BFL_BTCOEXIST; + if (bcm->board_vendor == PCI_VENDOR_ID_APPLE && + bcm->board_type == 0x4E && + bcm->board_revision > 0x40) + bcm->sprom.boardflags |= BCM43xx_BFL_PACTRL; /* antenna gain */ value = sprom[BCM43xx_SPROM_ANTENNA_GAIN]; -- cgit v1.2.3 From 5808bbbdf8c095745f0cac9110b245102243b243 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 15 Mar 2006 18:13:53 +0100 Subject: [PATCH] bcm43xx: properly mask txctl1 before writing it to hardware. This should not make a difference, but be careful to not trash the register. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 07a6169a0b3..cac604bc095 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -1690,8 +1690,8 @@ void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0064, radio_attenuation); if (radio->version == 0x2050) { bcm43xx_radio_write16(bcm, 0x0052, - (bcm43xx_radio_read16(bcm, 0x0052) & 0xFF8F) - | (txpower << 4)); + (bcm43xx_radio_read16(bcm, 0x0052) & ~0x0070) + | ((txpower << 4) & 0x0070)); } if (phy->type == BCM43xx_PHYTYPE_G) bcm43xx_phy_lo_adjust(bcm, 0); -- cgit v1.2.3 From 4a1821e4c7a84569f788b7667affe2743317b63f Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 18 Mar 2006 20:19:12 +0100 Subject: [PATCH] bcm43xx: remove check for mmio length, as it differs among platforms. (especially embedded) Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 30 ++++------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index e26507b11f0..6a877df2ecf 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3386,23 +3386,17 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) struct net_device *net_dev = bcm->net_dev; int err; int i; - void __iomem *ioaddr; - unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; + unsigned long mmio_start, mmio_flags, mmio_len; u32 coremask; err = pci_enable_device(pci_dev); if (err) { printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err); - err = -ENODEV; goto out; } - mmio_start = pci_resource_start(pci_dev, 0); - mmio_end = pci_resource_end(pci_dev, 0); mmio_flags = pci_resource_flags(pci_dev, 0); mmio_len = pci_resource_len(pci_dev, 0); - - /* make sure PCI base addr is MMIO */ if (!(mmio_flags & IORESOURCE_MEM)) { printk(KERN_ERR PFX "%s, region #0 not an MMIO resource, aborting\n", @@ -3410,39 +3404,23 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm) err = -ENODEV; goto err_pci_disable; } -//FIXME: Why is this check disabled for BCM947XX? What is the IO_SIZE there? -#ifndef CONFIG_BCM947XX - if (mmio_len != BCM43xx_IO_SIZE) { - printk(KERN_ERR PFX - "%s: invalid PCI mem region size(s), aborting\n", - pci_name(pci_dev)); - err = -ENODEV; - goto err_pci_disable; - } -#endif - err = pci_request_regions(pci_dev, KBUILD_MODNAME); if (err) { printk(KERN_ERR PFX "could not access PCI resources (%i)\n", err); goto err_pci_disable; } - /* enable PCI bus-mastering */ pci_set_master(pci_dev); - - /* ioremap MMIO region */ - ioaddr = ioremap(mmio_start, mmio_len); - if (!ioaddr) { + bcm->mmio_addr = ioremap(mmio_start, mmio_len); + if (!bcm->mmio_addr) { printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n", pci_name(pci_dev)); err = -EIO; goto err_pci_release; } - - net_dev->base_addr = (unsigned long)ioaddr; - bcm->mmio_addr = ioaddr; bcm->mmio_len = mmio_len; + net_dev->base_addr = (unsigned long)bcm->mmio_addr; bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID, &bcm->board_vendor); -- cgit v1.2.3 From 714eece7c7c300bbc5e8285890e7374958ca37f4 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 18 Mar 2006 21:28:46 +0100 Subject: [PATCH] bcm43xx: fix some gpio register trashing (hopefully :D) Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 16 +++++-- drivers/net/wireless/bcm43xx/bcm43xx_leds.h | 2 +- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 71 ++++++++++++++--------------- 3 files changed, 46 insertions(+), 43 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index 72a243aac6c..c8f5ad75d2a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -165,7 +165,7 @@ void bcm43xx_leds_exit(struct bcm43xx_private *bcm) led = &(bcm->leds[i]); bcm43xx_led_blink_stop(led, 1); } - bcm43xx_leds_turn_off(bcm); + bcm43xx_leds_switch_all(bcm, 0); } void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) @@ -268,18 +268,26 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity) bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); } -void bcm43xx_leds_turn_off(struct bcm43xx_private *bcm) +void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) { struct bcm43xx_led *led; - u16 ledctl = 0; + u16 ledctl; int i; + int bit_on; + ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL); for (i = 0; i < BCM43xx_NR_LEDS; i++) { led = &(bcm->leds[i]); if (led->behaviour == BCM43xx_LED_INACTIVE) continue; - if (led->activelow) + if (on) + bit_on = led->activelow ? 0 : 1; + else + bit_on = led->activelow ? 1 : 0; + if (bit_on) ledctl |= (1 << i); + else + ledctl &= ~(1 << i); } bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); } diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h index 6f18e2f95db..d3716cf3aeb 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.h @@ -51,6 +51,6 @@ enum { /* LED behaviour values */ int bcm43xx_leds_init(struct bcm43xx_private *bcm); void bcm43xx_leds_exit(struct bcm43xx_private *bcm); void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity); -void bcm43xx_leds_turn_off(struct bcm43xx_private *bcm); +void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on); #endif /* BCM43xx_LEDS_H_ */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 6a877df2ecf..eb8fca8279f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2182,13 +2182,10 @@ static int switch_to_gpio_core(struct bcm43xx_private *bcm) if (unlikely(err == -ENODEV)) { printk(KERN_ERR PFX "gpio error: " "Neither ChipCommon nor PCI core available!\n"); - return -ENODEV; - } else if (unlikely(err != 0)) - return -ENODEV; - } else if (unlikely(err != 0)) - return -ENODEV; + } + } - return 0; + return err; } /* Initialize the GPIOs @@ -2198,45 +2195,48 @@ static int bcm43xx_gpio_init(struct bcm43xx_private *bcm) { struct bcm43xx_coreinfo *old_core; int err; - u32 mask, value; + u32 mask, set; - value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - value &= ~0xc000; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value); + bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, + bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) + & 0xFFFF3FFF); - mask = 0x0000001F; - value = 0x0000000F; - bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, - bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL) & 0xFFF0); + bcm43xx_leds_switch_all(bcm, 0); bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F); - old_core = bcm->current_core; - - err = switch_to_gpio_core(bcm); - if (err) - return err; - - if (bcm->current_core->rev >= 2){ - mask |= 0x10; - value |= 0x10; - } + mask = 0x0000001F; + set = 0x0000000F; if (bcm->chip_id == 0x4301) { - mask |= 0x60; - value |= 0x60; + mask |= 0x0060; + set |= 0x0060; + } + if (0 /* FIXME: conditional unknown */) { + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) + | 0x0100); + mask |= 0x0180; + set |= 0x0180; } if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { - mask |= 0x200; - value |= 0x200; + bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, + bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) + | 0x0200); + mask |= 0x0200; + set |= 0x0200; } + if (bcm->current_core->rev >= 2) + mask |= 0x0010; /* FIXME: This is redundant. */ + old_core = bcm->current_core; + err = switch_to_gpio_core(bcm); + if (err) + goto out; bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, - (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | value); - + (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | set); err = bcm43xx_switch_core(bcm, old_core); - assert(err == 0); - - return 0; +out: + return err; } /* Turn off all GPIO stuff. Call this on module unload, for example. */ @@ -2384,11 +2384,6 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) goto err_gpio_cleanup; bcm43xx_radio_turn_on(bcm); - if (modparam_noleds) - bcm43xx_leds_turn_off(bcm); - else - bcm43xx_leds_update(bcm, 0); - bcm43xx_write16(bcm, 0x03E6, 0x0000); err = bcm43xx_phy_init(bcm); if (err) -- cgit v1.2.3 From 6ab5b8e670c4bb7ac0035ec3c6d6a161fae12009 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 19 Mar 2006 17:18:48 +0100 Subject: [PATCH] bcm43xx: merge all iwmode code into the set_iwmode function. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 65 +++++++++++++---------------- 1 file changed, 29 insertions(+), 36 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index eb8fca8279f..a85176325e9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2292,50 +2292,60 @@ void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, int iw_mode) { unsigned long flags; + struct net_device *net_dev = bcm->net_dev; u32 status; + u16 value; spin_lock_irqsave(&bcm->ieee->lock, flags); bcm->ieee->iw_mode = iw_mode; spin_unlock_irqrestore(&bcm->ieee->lock, flags); if (iw_mode == IW_MODE_MONITOR) - bcm->net_dev->type = ARPHRD_IEEE80211; + net_dev->type = ARPHRD_IEEE80211; else - bcm->net_dev->type = ARPHRD_ETHER; + net_dev->type = ARPHRD_ETHER; - if (!bcm->initialized) - return; - - bcm43xx_mac_suspend(bcm); status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Reset status to infrastructured mode */ status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR); - /*FIXME: We actually set promiscuous mode as well, until we don't - * get the HW mac filter working */ - status |= BCM43xx_SBF_MODE_NOTADHOC | BCM43xx_SBF_MODE_PROMISC; + status &= ~BCM43xx_SBF_MODE_PROMISC; + status |= BCM43xx_SBF_MODE_NOTADHOC; + +/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */ +status |= BCM43xx_SBF_MODE_PROMISC; switch (iw_mode) { case IW_MODE_MONITOR: - status |= (BCM43xx_SBF_MODE_PROMISC | - BCM43xx_SBF_MODE_MONITOR); + status |= BCM43xx_SBF_MODE_MONITOR; + status |= BCM43xx_SBF_MODE_PROMISC; break; case IW_MODE_ADHOC: status &= ~BCM43xx_SBF_MODE_NOTADHOC; break; case IW_MODE_MASTER: + status |= BCM43xx_SBF_MODE_AP; + break; case IW_MODE_SECOND: case IW_MODE_REPEAT: - /* TODO: No AP/Repeater mode for now :-/ */ - TODO(); + TODO(); /* TODO */ break; case IW_MODE_INFRA: /* nothing to be done here... */ break; default: - printk(KERN_ERR PFX "Unknown iwmode %d\n", iw_mode); + dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode); } - + if (net_dev->flags & IFF_PROMISC) + status |= BCM43xx_SBF_MODE_PROMISC; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); - bcm43xx_mac_enable(bcm); + + value = 0x0002; + if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) { + if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3) + value = 0x0064; + else + value = 0x0032; + } + bcm43xx_write16(bcm, 0x0612, value); } /* This is the opposite of bcm43xx_chip_init() */ @@ -2357,7 +2367,6 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); int err; - int iw_mode = bcm->ieee->iw_mode; int tmp; u32 value32; u16 value16; @@ -2411,20 +2420,9 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); value32 |= BCM43xx_SBF_MODE_NOTADHOC; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); - /*FIXME: For now, use promiscuous mode at all times; otherwise we don't - get broadcast or multicast packets */ - value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - value32 |= BCM43xx_SBF_MODE_PROMISC; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); - if (iw_mode == IW_MODE_MONITOR) { - value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - value32 |= BCM43xx_SBF_MODE_PROMISC; - value32 |= BCM43xx_SBF_MODE_MONITOR; - bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); - } value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); - value32 |= 0x100000; //FIXME: What's this? Is this correct? + value32 |= 0x100000; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32); if (bcm43xx_using_pio(bcm)) { @@ -2439,13 +2437,8 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm) /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */ bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000); - if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) { - if ((bcm->chip_id == 0x4306) && (bcm->chip_rev == 3)) - bcm43xx_write16(bcm, 0x0612, 0x0064); - else - bcm43xx_write16(bcm, 0x0612, 0x0032); - } else - bcm43xx_write16(bcm, 0x0612, 0x0002); + /* Initially set the wireless operation mode. */ + bcm43xx_set_iwmode(bcm, bcm->ieee->iw_mode); if (bcm->current_core->rev < 3) { bcm43xx_write16(bcm, 0x060E, 0x0000); -- cgit v1.2.3 From 0ac59daee5f7fbaab25784a643edede669b5419e Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sun, 19 Mar 2006 21:43:40 +0100 Subject: [PATCH] bcm43xx: some IRQ handler cleanups. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 65 +++++++++++++---------------- 1 file changed, 30 insertions(+), 35 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index a85176325e9..12c93d274ae 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1785,10 +1785,6 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS); } - /* We get spurious IRQs, althought they are masked. - * Assume they are void and ignore them. - */ - bcmirq_handled(~(bcm->irq_savedstate)); /* IRQ_PIO_WORKAROUND is handled in the top-half. */ bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND); #ifdef CONFIG_BCM43XX_DEBUG @@ -1809,41 +1805,31 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm) bcm43xx_unlock_mmio(bcm, flags); } -static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, - u32 reason, u32 mask) +static void pio_irq_workaround(struct bcm43xx_private *bcm, + u16 base, int queueidx) { - bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) - & 0x0001dc00; - bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON) - & 0x0000dc00; - bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON) - & 0x0000dc00; - bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) - & 0x0001dc00; + u16 rxctl; + + rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL); + if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE) + bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE; + else + bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE; +} +static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason) +{ if (bcm43xx_using_pio(bcm) && (bcm->current_core->rev < 3) && (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) { /* Apply a PIO specific workaround to the dma_reasons */ - -#define apply_pio_workaround(BASE, QNUM) \ - do { \ - if (bcm43xx_read16(bcm, BASE + BCM43xx_PIO_RXCTL) & BCM43xx_PIO_RXCTL_DATAAVAILABLE) \ - bcm->dma_reason[QNUM] |= 0x00010000; \ - else \ - bcm->dma_reason[QNUM] &= ~0x00010000; \ - } while (0) - - apply_pio_workaround(BCM43xx_MMIO_PIO1_BASE, 0); - apply_pio_workaround(BCM43xx_MMIO_PIO2_BASE, 1); - apply_pio_workaround(BCM43xx_MMIO_PIO3_BASE, 2); - apply_pio_workaround(BCM43xx_MMIO_PIO4_BASE, 3); - -#undef apply_pio_workaround + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0); + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1); + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2); + pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3); } - bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, - reason & mask); + bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason); bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON, bcm->dma_reason[0]); @@ -1860,7 +1846,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re { irqreturn_t ret = IRQ_HANDLED; struct bcm43xx_private *bcm = dev_id; - u32 reason, mask; + u32 reason; if (!bcm) return IRQ_NONE; @@ -1873,11 +1859,20 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re ret = IRQ_NONE; goto out; } - mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); - if (!(reason & mask)) + reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); + if (!reason) goto out; - bcm43xx_interrupt_ack(bcm, reason, mask); + bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) + & 0x0001dc00; + bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON) + & 0x0000dc00; + bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON) + & 0x0000dc00; + bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) + & 0x0001dc00; + + bcm43xx_interrupt_ack(bcm, reason); /* Only accept IRQs, if we are initialized properly. * This avoids an RX race while initializing. -- cgit v1.2.3 From 6ecb26904c9db15ca964d60b9483f19dc51bda5b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 20 Mar 2006 00:01:04 +0100 Subject: [PATCH] bcm43xx: set default attenuation values. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 21 +++-- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 9 +- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 30 +++--- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 131 +++++++++++++++++++++++++-- drivers/net/wireless/bcm43xx/bcm43xx_radio.h | 5 + 5 files changed, 158 insertions(+), 38 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 8820012b4b3..1fca1f9c48f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -507,14 +507,23 @@ struct bcm43xx_radioinfo { u16 version; u8 revision; - /* 0: baseband attenuation, - * 1: radio attenuation, - * 2: tx_CTL1 - * 3: tx_CTL2 - */ - u16 txpower[4]; /* Desired TX power in dBm Q5.2 */ u16 txpower_desired; + /* TX Power control values. */ + union { + /* B/G PHY */ + struct { + u16 baseband_atten; + u16 radio_atten; + u16 txctl1; + u16 txctl2; + }; + /* A PHY */ + struct { + u16 txpwr_offset; + }; + }; + /* Current Interference Mitigation mode */ int interfmode; /* Stack of saved values from the Interference Mitigation code */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 12c93d274ae..e680d2acc44 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -560,12 +560,9 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) radio->revision = revision; /* Set default attenuation values. */ - radio->txpower[0] = 2; - radio->txpower[1] = 2; - if (revision == 1) - radio->txpower[2] = 3; - else - radio->txpower[2] = 0; + radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm); + radio->radio_atten = bcm43xx_default_radio_attenuation(bcm); + radio->txctl1 = bcm43xx_default_txctl1(bcm); if (phy->type == BCM43xx_PHYTYPE_A) radio->txpower_desired = bcm->sprom.maxpower_aphy; else diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 1ce9a459990..054c64e462f 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -220,9 +220,9 @@ static void bcm43xx_phy_init_pctl(struct bcm43xx_private *bcm) bcm43xx_radio_write16(bcm, 0x0076, bcm43xx_radio_read16(bcm, 0x0076) | 0x0084); } else { - saved_batt = radio->txpower[0]; - saved_ratt = radio->txpower[1]; - saved_txctl1 = radio->txpower[2]; + saved_batt = radio->baseband_atten; + saved_ratt = radio->radio_atten; + saved_txctl1 = radio->txctl1; if ((radio->revision >= 6) && (radio->revision <= 8) && /*FIXME: incomplete specs for 5 < revision < 9 */ 0) bcm43xx_radio_set_txpower_bg(bcm, 0xB, 0x1F, 0); @@ -1039,7 +1039,7 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) bcm43xx_radio_write16(bcm, 0x0078, radio->initval); bcm43xx_radio_write16(bcm, 0x0052, (bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0) - | radio->txpower[3]); + | radio->txctl2); } if (phy->connected) { @@ -1259,7 +1259,6 @@ struct bcm43xx_lopair * bcm43xx_find_lopair(struct bcm43xx_private *bcm, if (baseband_attenuation > 6) baseband_attenuation = 6; assert(radio_attenuation < 10); - assert(tx == 0 || tx == 3); if (tx == 3) { return bcm43xx_get_lopair(phy, @@ -1275,9 +1274,9 @@ struct bcm43xx_lopair * bcm43xx_current_lopair(struct bcm43xx_private *bcm) struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); return bcm43xx_find_lopair(bcm, - radio->txpower[0], - radio->txpower[1], - radio->txpower[2]); + radio->baseband_atten, + radio->radio_atten, + radio->txctl1); } /* Adjust B/G LO */ @@ -1311,7 +1310,7 @@ static void bcm43xx_phy_lo_g_measure_txctl2(struct bcm43xx_private *bcm) txctl2 = i; } } - radio->txpower[3] = txctl2; + radio->txctl2 = txctl2; } static @@ -1530,8 +1529,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) r31 = 0; } bcm43xx_radio_write16(bcm, 0x43, i); - bcm43xx_radio_write16(bcm, 0x52, - radio->txpower[3]); + bcm43xx_radio_write16(bcm, 0x52, radio->txctl2); udelay(10); bcm43xx_phy_set_baseband_attenuation(bcm, j * 2); @@ -1573,7 +1571,7 @@ void bcm43xx_phy_lo_g_measure(struct bcm43xx_private *bcm) } bcm43xx_radio_write16(bcm, 0x43, i - 9); bcm43xx_radio_write16(bcm, 0x52, - radio->txpower[3] + radio->txctl2 | (3/*txctl1*/ << 4));//FIXME: shouldn't txctl1 be zero here and 3 in the loop above? udelay(10); @@ -1780,9 +1778,9 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) } /* Calculate the new attenuation values. */ - baseband_attenuation = radio->txpower[0]; + baseband_attenuation = radio->baseband_atten; baseband_attenuation += baseband_att_delta; - radio_attenuation = radio->txpower[1]; + radio_attenuation = radio->radio_atten; radio_attenuation += radio_att_delta; /* Get baseband and radio attenuation values into their permitted ranges. @@ -1807,7 +1805,7 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) } baseband_attenuation = limit_value(baseband_attenuation, 0, 11); - txpower = radio->txpower[2]; + txpower = radio->txctl1; if ((radio->version == 0x2050) && (radio->revision == 2)) { if (radio_attenuation <= 1) { if (txpower == 0) { @@ -1829,7 +1827,7 @@ void bcm43xx_phy_xmitpower(struct bcm43xx_private *bcm) } } } - radio->txpower[2] = txpower; + radio->txctl1 = txpower; baseband_attenuation = limit_value(baseband_attenuation, 0, 11); radio_attenuation = limit_value(radio_attenuation, 0, 9); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index cac604bc095..4e8d8c936ab 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -1652,7 +1652,7 @@ void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower) bcm43xx_ilt_write(bcm, 0x3001, dac); - radio->txpower[0] = txpower; + radio->txpwr_offset = txpower; TODO(); //TODO: FuncPlaceholder (Adjust BB loft cancel) @@ -1666,17 +1666,14 @@ void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); if (baseband_attenuation == 0xFFFF) - baseband_attenuation = radio->txpower[0]; - else - radio->txpower[0] = baseband_attenuation; + baseband_attenuation = radio->baseband_atten; if (radio_attenuation == 0xFFFF) - radio_attenuation = radio->txpower[1]; - else - radio->txpower[1] = radio_attenuation; + radio_attenuation = radio->radio_atten; if (txpower == 0xFFFF) - txpower = radio->txpower[2]; - else - radio->txpower[2] = txpower; + txpower = radio->txctl1; + radio->baseband_atten = baseband_attenuation; + radio->radio_atten = radio_attenuation; + radio->txctl1 = txpower; assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11); if (radio->revision < 6) @@ -1693,10 +1690,124 @@ void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, (bcm43xx_radio_read16(bcm, 0x0052) & ~0x0070) | ((txpower << 4) & 0x0070)); } + //FIXME: The spec is very weird and unclear here. if (phy->type == BCM43xx_PHYTYPE_G) bcm43xx_phy_lo_adjust(bcm, 0); } +u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + + if (radio->version == 0x2050 && radio->revision < 6) + return 0; + return 2; +} + +u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 att = 0xFFFF; + + if (phy->type == BCM43xx_PHYTYPE_A) + return 0x60; + + switch (radio->version) { + case 0x2053: + switch (radio->revision) { + case 1: + att = 6; + break; + } + break; + case 0x2050: + switch (radio->revision) { + case 0: + att = 5; + break; + case 1: + if (phy->type == BCM43xx_PHYTYPE_G) { + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x421 && + bcm->board_revision >= 30) + att = 3; + else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x416) + att = 3; + else + att = 1; + } else { + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x421 && + bcm->board_revision >= 30) + att = 7; + else + att = 6; + } + break; + case 2: + if (phy->type == BCM43xx_PHYTYPE_G) { + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x421 && + bcm->board_revision >= 30) + att = 3; + else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x416) + att = 5; + else if (bcm->chip_id == 0x4320) + att = 4; + else + att = 3; + } else + att = 6; + break; + case 3: + att = 5; + break; + case 4: + case 5: + att = 1; + break; + case 6: + case 7: + att = 5; + break; + case 8: + att = 0x1A; + break; + case 9: + default: + att = 5; + } + } + if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && + bcm->board_type == 0x421) { + if (bcm->board_revision < 0x43) + att = 2; + else if (bcm->board_revision < 0x51) + att = 3; + } + if (att == 0xFFFF) + att = 5; + + return att; +} + +u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm) +{ + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + + if (radio->version != 0x2050) + return 0; + if (radio->revision == 1) + return 3; + if (radio->revision < 6) + return 2; + if (radio->revision == 8) + return 1; + return 0; +} void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm) { diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h index a5d2e10d5d9..9ed18039fa3 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.h @@ -72,6 +72,11 @@ void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower); void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, u16 baseband_attenuation, u16 attenuation, u16 txpower); + +u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm); +u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm); +u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm); + void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val); void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm); -- cgit v1.2.3 From e382c234cbc6fcd76e9ed1168c77fe88d75df73c Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Tue, 21 Mar 2006 18:16:28 +0100 Subject: [PATCH] bcm43xx: sync interference mitigation code to the specs. This also includes a rewritten valuesave-stack. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 12 +- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 447 ++++++++++++++++++--------- 2 files changed, 309 insertions(+), 150 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 1fca1f9c48f..57fcaafcf7d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -526,8 +526,16 @@ struct bcm43xx_radioinfo { /* Current Interference Mitigation mode */ int interfmode; - /* Stack of saved values from the Interference Mitigation code */ - u16 interfstack[20]; + /* Stack of saved values from the Interference Mitigation code. + * Each value in the stack is layed out as follows: + * bit 0-11: offset + * bit 12-15: register ID + * bit 16-32: value + * register ID is: 0x1 PHY, 0x2 Radio, 0x3 ILT + */ +#define BCM43xx_INTERFSTACK_SIZE 26 + u32 interfstack[BCM43xx_INTERFSTACK_SIZE]; + /* Saved values from the NRSSI Slope calculation */ s16 nrssi[2]; s32 nrssislope; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 4e8d8c936ab..63aae43ba83 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -879,24 +879,76 @@ void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) } } -/* Helper macros to save on and restore values from the radio->interfstack */ -#ifdef stack_save -# undef stack_save -#endif -#ifdef stack_restore -# undef stack_restore -#endif -#define stack_save(value) \ +/* Stack implementation to save/restore values from the + * interference mitigation code. + * It is save to restore values in random order. + */ +static void _stack_save(u32 *_stackptr, size_t *stackidx, + u8 id, u16 offset, u16 value) +{ + u32 *stackptr = &(_stackptr[*stackidx]); + + assert((offset & 0xF000) == 0x0000); + assert((id & 0xF0) == 0x00); + *stackptr = offset; + *stackptr |= ((u32)id) << 12; + *stackptr |= ((u32)value) << 16; + (*stackidx)++; + assert(*stackidx < BCM43xx_INTERFSTACK_SIZE); +} + +static u16 _stack_restore(u32 *stackptr, + u8 id, u16 offset) +{ + size_t i; + + assert((offset & 0xF000) == 0x0000); + assert((id & 0xF0) == 0x00); + for (i = 0; i < BCM43xx_INTERFSTACK_SIZE; i++, stackptr++) { + if ((*stackptr & 0x00000FFF) != offset) + continue; + if (((*stackptr & 0x0000F000) >> 12) != id) + continue; + return ((*stackptr & 0xFFFF0000) >> 16); + } + assert(0); + + return 0; +} + +#define phy_stacksave(offset) \ do { \ - assert(i < ARRAY_SIZE(radio->interfstack)); \ - stack[i++] = (value); \ + _stack_save(stack, &stackidx, 0x1, (offset), \ + bcm43xx_phy_read(bcm, (offset))); \ + } while (0) +#define phy_stackrestore(offset) \ + do { \ + bcm43xx_phy_write(bcm, (offset), \ + _stack_restore(stack, 0x1, \ + (offset))); \ + } while (0) +#define radio_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x2, (offset), \ + bcm43xx_radio_read16(bcm, (offset))); \ + } while (0) +#define radio_stackrestore(offset) \ + do { \ + bcm43xx_radio_write16(bcm, (offset), \ + _stack_restore(stack, 0x2, \ + (offset))); \ + } while (0) +#define ilt_stacksave(offset) \ + do { \ + _stack_save(stack, &stackidx, 0x3, (offset), \ + bcm43xx_ilt_read(bcm, (offset))); \ + } while (0) +#define ilt_stackrestore(offset) \ + do { \ + bcm43xx_ilt_write(bcm, (offset), \ + _stack_restore(stack, 0x3, \ + (offset))); \ } while (0) - -#define stack_restore() \ - ({ \ - assert(i < ARRAY_SIZE(radio->interfstack)); \ - stack[i++]; \ - }) static void bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm, @@ -904,144 +956,231 @@ bcm43xx_radio_interference_mitigation_enable(struct bcm43xx_private *bcm, { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - int i = 0; - u16 *stack = radio->interfstack; u16 tmp, flipped; + u32 tmp32; + size_t stackidx = 0; + u32 *stack = radio->interfstack; switch (mode) { case BCM43xx_RADIO_INTERFMODE_NONWLAN: if (phy->rev != 1) { bcm43xx_phy_write(bcm, 0x042B, - bcm43xx_phy_read(bcm, 0x042B) & 0x0800); + bcm43xx_phy_read(bcm, 0x042B) | 0x0800); bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & ~0x4000); break; } + radio_stacksave(0x0078); tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E); flipped = flip_4bit(tmp); - if ((flipped >> 1) >= 4) - tmp = flipped - 3; - tmp = flip_4bit(tmp); - bcm43xx_radio_write16(bcm, 0x0078, tmp << 1); + if (flipped < 10 && flipped >= 8) + flipped = 7; + else if (flipped >= 10) + flipped -= 3; + flipped = flip_4bit(flipped); + flipped = (flipped << 1) | 0x0020; + bcm43xx_radio_write16(bcm, 0x0078, flipped); bcm43xx_calc_nrssi_threshold(bcm); - if (bcm->current_core->rev < 5) { - stack_save(bcm43xx_phy_read(bcm, 0x0406)); - bcm43xx_phy_write(bcm, 0x0406, 0x7E28); - } else { - stack_save(bcm43xx_phy_read(bcm, 0x04C0)); - stack_save(bcm43xx_phy_read(bcm, 0x04C1)); - bcm43xx_phy_write(bcm, 0x04C0, 0x3E04); - bcm43xx_phy_write(bcm, 0x04C1, 0x0640); - } + phy_stacksave(0x0406); + bcm43xx_phy_write(bcm, 0x0406, 0x7E28); bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) | 0x0800); bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) | 0x1000); - stack_save(bcm43xx_phy_read(bcm, 0x04A0)); + phy_stacksave(0x04A0); bcm43xx_phy_write(bcm, 0x04A0, (bcm43xx_phy_read(bcm, 0x04A0) & 0xC0C0) | 0x0008); - stack_save(bcm43xx_phy_read(bcm, 0x04A1)); + phy_stacksave(0x04A1); bcm43xx_phy_write(bcm, 0x04A1, (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0C0) | 0x0605); - stack_save(bcm43xx_phy_read(bcm, 0x04A2)); + phy_stacksave(0x04A2); bcm43xx_phy_write(bcm, 0x04A2, (bcm43xx_phy_read(bcm, 0x04A2) & 0xC0C0) | 0x0204); - stack_save(bcm43xx_phy_read(bcm, 0x04A8)); + phy_stacksave(0x04A8); bcm43xx_phy_write(bcm, 0x04A8, - (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0403); - stack_save(bcm43xx_phy_read(bcm, 0x04AB)); + (bcm43xx_phy_read(bcm, 0x04A8) & 0xC0C0) | 0x0803); + phy_stacksave(0x04AB); bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0504); + (bcm43xx_phy_read(bcm, 0x04AB) & 0xC0C0) | 0x0605); - stack_save(bcm43xx_phy_read(bcm, 0x04A7)); + phy_stacksave(0x04A7); bcm43xx_phy_write(bcm, 0x04A7, 0x0002); - stack_save(bcm43xx_phy_read(bcm, 0x04A3)); + phy_stacksave(0x04A3); bcm43xx_phy_write(bcm, 0x04A3, 0x287A); - stack_save(bcm43xx_phy_read(bcm, 0x04A9)); + phy_stacksave(0x04A9); bcm43xx_phy_write(bcm, 0x04A9, 0x2027); - stack_save(bcm43xx_phy_read(bcm, 0x0493)); + phy_stacksave(0x0493); bcm43xx_phy_write(bcm, 0x0493, 0x32F5); - stack_save(bcm43xx_phy_read(bcm, 0x04AA)); + phy_stacksave(0x04AA); bcm43xx_phy_write(bcm, 0x04AA, 0x2027); - stack_save(bcm43xx_phy_read(bcm, 0x04AC)); + phy_stacksave(0x04AC); bcm43xx_phy_write(bcm, 0x04AC, 0x32F5); break; case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: - if (bcm43xx_phy_read(bcm, 0x0033) == 0x0800) + if (bcm43xx_phy_read(bcm, 0x0033) & 0x0800) break; radio->aci_enable = 1; - stack_save(bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD)); - stack_save(bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS)); - if (bcm->current_core->rev < 5) { - stack_save(bcm43xx_phy_read(bcm, 0x0406)); + phy_stacksave(BCM43xx_PHY_RADIO_BITFIELD); + phy_stacksave(BCM43xx_PHY_G_CRS); + if (phy->rev < 2) { + phy_stacksave(0x0406); } else { - stack_save(bcm43xx_phy_read(bcm, 0x04C0)); - stack_save(bcm43xx_phy_read(bcm, 0x04C1)); + phy_stacksave(0x04C0); + phy_stacksave(0x04C1); } - stack_save(bcm43xx_phy_read(bcm, 0x0033)); - stack_save(bcm43xx_phy_read(bcm, 0x04A7)); - stack_save(bcm43xx_phy_read(bcm, 0x04A3)); - stack_save(bcm43xx_phy_read(bcm, 0x04A9)); - stack_save(bcm43xx_phy_read(bcm, 0x04AA)); - stack_save(bcm43xx_phy_read(bcm, 0x04AC)); - stack_save(bcm43xx_phy_read(bcm, 0x0493)); - stack_save(bcm43xx_phy_read(bcm, 0x04A1)); - stack_save(bcm43xx_phy_read(bcm, 0x04A0)); - stack_save(bcm43xx_phy_read(bcm, 0x04A2)); - stack_save(bcm43xx_phy_read(bcm, 0x048A)); - stack_save(bcm43xx_phy_read(bcm, 0x04A8)); - stack_save(bcm43xx_phy_read(bcm, 0x04AB)); + phy_stacksave(0x0033); + phy_stacksave(0x04A7); + phy_stacksave(0x04A3); + phy_stacksave(0x04A9); + phy_stacksave(0x04AA); + phy_stacksave(0x04AC); + phy_stacksave(0x0493); + phy_stacksave(0x04A1); + phy_stacksave(0x04A0); + phy_stacksave(0x04A2); + phy_stacksave(0x048A); + phy_stacksave(0x04A8); + phy_stacksave(0x04AB); + if (phy->rev == 2) { + phy_stacksave(0x04AD); + phy_stacksave(0x04AE); + } else if (phy->rev >= 3) { + phy_stacksave(0x04AD); + phy_stacksave(0x0415); + phy_stacksave(0x0416); + phy_stacksave(0x0417); + ilt_stacksave(0x1A00 + 0x2); + ilt_stacksave(0x1A00 + 0x3); + } + phy_stacksave(0x042B); + phy_stacksave(0x048C); bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, - bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) & 0xEFFF); + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) + & ~0x1000); bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xEFFF) | 0x0002); + (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) + & 0xFFFC) | 0x0002); - bcm43xx_phy_write(bcm, 0x04A7, 0x0800); - bcm43xx_phy_write(bcm, 0x04A3, 0x287A); - bcm43xx_phy_write(bcm, 0x04A9, 0x2027); - bcm43xx_phy_write(bcm, 0x0493, 0x32F5); - bcm43xx_phy_write(bcm, 0x04AA, 0x2027); - bcm43xx_phy_write(bcm, 0x04AC, 0x32F5); + bcm43xx_phy_write(bcm, 0x0033, 0x0800); + bcm43xx_phy_write(bcm, 0x04A3, 0x2027); + bcm43xx_phy_write(bcm, 0x04A9, 0x1CA8); + bcm43xx_phy_write(bcm, 0x0493, 0x287A); + bcm43xx_phy_write(bcm, 0x04AA, 0x1CA8); + bcm43xx_phy_write(bcm, 0x04AC, 0x287A); bcm43xx_phy_write(bcm, 0x04A0, - (bcm43xx_phy_read(bcm, 0x04A0) & 0xFFC0) | 0x001A); - if (bcm->current_core->rev < 5) { - bcm43xx_phy_write(bcm, 0x0406, 0x280D); - } else { - bcm43xx_phy_write(bcm, 0x04C0, 0x0640); + (bcm43xx_phy_read(bcm, 0x04A0) + & 0xFFC0) | 0x001A); + bcm43xx_phy_write(bcm, 0x04A7, 0x000D); + + if (phy->rev < 2) { + bcm43xx_phy_write(bcm, 0x0406, 0xFF0D); + } else if (phy->rev == 2) { + bcm43xx_phy_write(bcm, 0x04C0, 0xFFFF); bcm43xx_phy_write(bcm, 0x04C1, 0x00A9); + } else { + bcm43xx_phy_write(bcm, 0x04C0, 0x00C1); + bcm43xx_phy_write(bcm, 0x04C1, 0x0059); } bcm43xx_phy_write(bcm, 0x04A1, - (bcm43xx_phy_read(bcm, 0x04A1) & 0xC0FF) | 0x1800); + (bcm43xx_phy_read(bcm, 0x04A1) + & 0xC0FF) | 0x1800); bcm43xx_phy_write(bcm, 0x04A1, - (bcm43xx_phy_read(bcm, 0x04A1) & 0xFFC0) | 0x0016); - bcm43xx_phy_write(bcm, 0x04A2, - (bcm43xx_phy_read(bcm, 0x04A2) & 0xF0FF) | 0x0900); - bcm43xx_phy_write(bcm, 0x04A0, - (bcm43xx_phy_read(bcm, 0x04A0) & 0xF0FF) | 0x0700); - bcm43xx_phy_write(bcm, 0x04A2, - (bcm43xx_phy_read(bcm, 0x04A2) & 0xFFF0) | 0x000D); + (bcm43xx_phy_read(bcm, 0x04A1) + & 0xFFC0) | 0x0015); bcm43xx_phy_write(bcm, 0x04A8, - (bcm43xx_phy_read(bcm, 0x04A8) & 0xCFFF) | 0x1000); + (bcm43xx_phy_read(bcm, 0x04A8) + & 0xCFFF) | 0x1000); bcm43xx_phy_write(bcm, 0x04A8, - (bcm43xx_phy_read(bcm, 0x04A8) & 0xF0FF) | 0x0A00); + (bcm43xx_phy_read(bcm, 0x04A8) + & 0xF0FF) | 0x0A00); bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) & 0xCFFF) | 0x1000); + (bcm43xx_phy_read(bcm, 0x04AB) + & 0xCFFF) | 0x1000); bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0800); + (bcm43xx_phy_read(bcm, 0x04AB) + & 0xF0FF) | 0x0800); bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) & 0xFFCF) | 0x0010); + (bcm43xx_phy_read(bcm, 0x04AB) + & 0xFFCF) | 0x0010); bcm43xx_phy_write(bcm, 0x04AB, - (bcm43xx_phy_read(bcm, 0x04AB) & 0xFFF0) | 0x0006); + (bcm43xx_phy_read(bcm, 0x04AB) + & 0xFFF0) | 0x0005); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) + & 0xFFCF) | 0x0010); + bcm43xx_phy_write(bcm, 0x04A8, + (bcm43xx_phy_read(bcm, 0x04A8) + & 0xFFF0) | 0x0006); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) + & 0xF0FF) | 0x0800); + bcm43xx_phy_write(bcm, 0x04A0, + (bcm43xx_phy_read(bcm, 0x04A0) + & 0xF0FF) | 0x0500); + bcm43xx_phy_write(bcm, 0x04A2, + (bcm43xx_phy_read(bcm, 0x04A2) + & 0xFFF0) | 0x000B); + if (phy->rev >= 3) { + bcm43xx_phy_write(bcm, 0x048A, + bcm43xx_phy_read(bcm, 0x048A) + & ~0x8000); + bcm43xx_phy_write(bcm, 0x0415, + (bcm43xx_phy_read(bcm, 0x0415) + & 0x8000) | 0x36D8); + bcm43xx_phy_write(bcm, 0x0416, + (bcm43xx_phy_read(bcm, 0x0416) + & 0x8000) | 0x36D8); + bcm43xx_phy_write(bcm, 0x0417, + (bcm43xx_phy_read(bcm, 0x0417) + & 0xFE00) | 0x016D); + } else { + bcm43xx_phy_write(bcm, 0x048A, + bcm43xx_phy_read(bcm, 0x048A) + | 0x1000); + bcm43xx_phy_write(bcm, 0x048A, + (bcm43xx_phy_read(bcm, 0x048A) + & 0x9FFF) | 0x2000); + tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET); + if (!(tmp32 & 0x800)) { + tmp32 |= 0x800; + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + tmp32); + } + } + if (phy->rev >= 2) { + bcm43xx_phy_write(bcm, 0x042B, + bcm43xx_phy_read(bcm, 0x042B) + | 0x0800); + } + bcm43xx_phy_write(bcm, 0x048C, + (bcm43xx_phy_read(bcm, 0x048C) + & 0xF0FF) | 0x0200); + if (phy->rev == 2) { + bcm43xx_phy_write(bcm, 0x04AE, + (bcm43xx_phy_read(bcm, 0x04AE) + & 0xFF00) | 0x007F); + bcm43xx_phy_write(bcm, 0x04AD, + (bcm43xx_phy_read(bcm, 0x04AD) + & 0x00FF) | 0x1300); + } else if (phy->rev >= 6) { + bcm43xx_ilt_write(bcm, 0x1A00 + 0x3, 0x007F); + bcm43xx_ilt_write(bcm, 0x1A00 + 0x2, 0x007F); + bcm43xx_phy_write(bcm, 0x04AD, + bcm43xx_phy_read(bcm, 0x04AD) + & 0x00FF); + } bcm43xx_calc_nrssi_slope(bcm); break; default: @@ -1055,9 +1194,8 @@ bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - int i = 0; - u16 *stack = radio->interfstack; - u16 tmp, flipped; + u32 tmp32; + u32 *stack = radio->interfstack; switch (mode) { case BCM43xx_RADIO_INTERFMODE_NONWLAN: @@ -1065,71 +1203,80 @@ bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x4000); + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000); break; } - tmp = (bcm43xx_radio_read16(bcm, 0x0078) & 0x001E); - flipped = flip_4bit(tmp); - if ((flipped >> 1) >= 0x000C) - tmp = flipped + 3; - tmp = flip_4bit(tmp); - bcm43xx_radio_write16(bcm, 0x0078, tmp << 1); - + phy_stackrestore(0x0078); bcm43xx_calc_nrssi_threshold(bcm); - - if (bcm->current_core->rev < 5) { - bcm43xx_phy_write(bcm, 0x0406, stack_restore()); - } else { - bcm43xx_phy_write(bcm, 0x04C0, stack_restore()); - bcm43xx_phy_write(bcm, 0x04C1, stack_restore()); - } + phy_stackrestore(0x0406); bcm43xx_phy_write(bcm, 0x042B, bcm43xx_phy_read(bcm, 0x042B) & ~0x0800); - - if (!bcm->bad_frames_preempt) + if (!bcm->bad_frames_preempt) { bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, - bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) & ~(1 << 11)); + bcm43xx_phy_read(bcm, BCM43xx_PHY_RADIO_BITFIELD) + & ~(1 << 11)); + } bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, - bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x4000); - bcm43xx_phy_write(bcm, 0x04A0, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A1, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A2, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A8, stack_restore()); - bcm43xx_phy_write(bcm, 0x04AB, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A7, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A3, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A9, stack_restore()); - bcm43xx_phy_write(bcm, 0x0493, stack_restore()); - bcm43xx_phy_write(bcm, 0x04AA, stack_restore()); - bcm43xx_phy_write(bcm, 0x04AC, stack_restore()); + bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) | 0x4000); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A7); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); break; case BCM43xx_RADIO_INTERFMODE_MANUALWLAN: - if (bcm43xx_phy_read(bcm, 0x0033) != 0x0800) + if (!(bcm43xx_phy_read(bcm, 0x0033) & 0x0800)) break; radio->aci_enable = 0; - bcm43xx_phy_write(bcm, BCM43xx_PHY_RADIO_BITFIELD, stack_restore()); - bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, stack_restore()); - if (bcm->current_core->rev < 5) { - bcm43xx_phy_write(bcm, 0x0406, stack_restore()); - } else { - bcm43xx_phy_write(bcm, 0x04C0, stack_restore()); - bcm43xx_phy_write(bcm, 0x04C1, stack_restore()); + phy_stackrestore(BCM43xx_PHY_RADIO_BITFIELD); + phy_stackrestore(BCM43xx_PHY_G_CRS); + phy_stackrestore(0x0033); + phy_stackrestore(0x04A3); + phy_stackrestore(0x04A9); + phy_stackrestore(0x0493); + phy_stackrestore(0x04AA); + phy_stackrestore(0x04AC); + phy_stackrestore(0x04A0); + phy_stackrestore(0x04A7); + if (phy->rev >= 2) { + phy_stackrestore(0x04C0); + phy_stackrestore(0x04C1); + } else + phy_stackrestore(0x0406); + phy_stackrestore(0x04A1); + phy_stackrestore(0x04AB); + phy_stackrestore(0x04A8); + if (phy->rev == 2) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x04AE); + } else if (phy->rev >= 3) { + phy_stackrestore(0x04AD); + phy_stackrestore(0x0415); + phy_stackrestore(0x0416); + phy_stackrestore(0x0417); + ilt_stackrestore(0x1A00 + 0x2); + ilt_stackrestore(0x1A00 + 0x3); + } + phy_stackrestore(0x04A2); + phy_stackrestore(0x04A8); + phy_stackrestore(0x042B); + phy_stackrestore(0x048C); + tmp32 = bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET); + if (tmp32 & 0x800) { + tmp32 &= ~0x800; + bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, + BCM43xx_UCODEFLAGS_OFFSET, + tmp32); } - bcm43xx_phy_write(bcm, 0x0033, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A7, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A3, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A9, stack_restore()); - bcm43xx_phy_write(bcm, 0x04AA, stack_restore()); - bcm43xx_phy_write(bcm, 0x04AC, stack_restore()); - bcm43xx_phy_write(bcm, 0x0493, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A1, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A0, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A2, stack_restore()); - bcm43xx_phy_write(bcm, 0x04A8, stack_restore()); - bcm43xx_phy_write(bcm, 0x04AB, stack_restore()); - bcm43xx_calc_nrssi_slope(bcm); break; default: @@ -1137,8 +1284,12 @@ bcm43xx_radio_interference_mitigation_disable(struct bcm43xx_private *bcm, } } -#undef stack_save -#undef stack_restore +#undef phy_stacksave +#undef phy_stackrestore +#undef radio_stacksave +#undef radio_stackrestore +#undef ilt_stacksave +#undef ilt_stackrestore int bcm43xx_radio_set_interference_mitigation(struct bcm43xx_private *bcm, int mode) -- cgit v1.2.3 From cf017e1b6f625978288e2cd8ede04f8185b97c08 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 22 Mar 2006 17:58:47 +0100 Subject: [PATCH] bcm43xx: fix nrssi_threshold calculation. patch by doctorzoidberg. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_radio.c | 72 +++++++++++++--------------- 1 file changed, 33 insertions(+), 39 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 63aae43ba83..af5c0bff169 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c @@ -782,41 +782,30 @@ void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); - s16 threshold; + s32 threshold; s32 a, b; - int tmp; s16 tmp16; u16 tmp_u16; switch (phy->type) { case BCM43xx_PHYTYPE_B: { - int radiotype = 0; - - if (phy->rev < 2) - return; if (radio->version != 0x2050) return; if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) return; - tmp = radio->revision; - if ((radio->manufact == 0x175 && tmp == 5) || - (radio->manufact == 0x17F && (tmp == 3 || tmp == 4))) - radiotype = 1; - - if (radiotype == 1) { + if (radio->revision >= 6) { + threshold = (radio->nrssi[1] - radio->nrssi[0]) * 32; + threshold += 20 * (radio->nrssi[0] + 1); + threshold /= 40; + } else threshold = radio->nrssi[1] - 5; - } else { - threshold = 40 * radio->nrssi[0]; - threshold += 33 * (radio->nrssi[1] - radio->nrssi[0]); - threshold += 20; - threshold /= 10; - } + threshold = limit_value(threshold, 0, 0x3E); bcm43xx_phy_read(bcm, 0x0020); /* dummy read */ bcm43xx_phy_write(bcm, 0x0020, (((u16)threshold) << 8) | 0x001C); - if (radiotype == 1) { + if (radio->revision >= 6) { bcm43xx_phy_write(bcm, 0x0087, 0x0E0D); bcm43xx_phy_write(bcm, 0x0086, 0x0C0B); bcm43xx_phy_write(bcm, 0x0085, 0x0A09); @@ -844,33 +833,38 @@ void bcm43xx_calc_nrssi_threshold(struct bcm43xx_private *bcm) & 0xF000) | 0x0AED); } } else { - tmp = radio->interfmode; - if (tmp == BCM43xx_RADIO_INTERFMODE_NONWLAN) { - a = -13; - b = -17; - } else if (tmp == BCM43xx_RADIO_INTERFMODE_NONE && - !radio->aci_enable) { - a = -13; - b = -10; + if (radio->interfmode == BCM43xx_RADIO_INTERFMODE_NONWLAN) { + a = 0xE; + b = 0xA; + } else if (!radio->aci_wlan_automatic && radio->aci_enable) { + a = 0x13; + b = 0x12; } else { - a = -8; - b = -9; + a = 0xE; + b = 0x11; } - a += 0x1B; - a *= radio->nrssi[1] - radio->nrssi[0]; - a += radio->nrssi[0] * 0x40; - a /= 64; - b += 0x1B; - b *= radio->nrssi[1] - radio->nrssi[0]; - b += radio->nrssi[0] * 0x40; - b /= 64; + a = a * (radio->nrssi[1] - radio->nrssi[0]); + a += (radio->nrssi[0] << 6); + if (a < 32) + a += 31; + else + a += 32; + a = a >> 6; a = limit_value(a, -31, 31); + + b = b * (radio->nrssi[1] - radio->nrssi[0]); + b += (radio->nrssi[0] << 6); + if (b < 32) + b += 31; + else + b += 32; + b = b >> 6; b = limit_value(b, -31, 31); tmp_u16 = bcm43xx_phy_read(bcm, 0x048A) & 0xF000; - tmp_u16 |= ((u32)a & 0x003F); - tmp_u16 |= (((u32)b & 0x003F) << 6); + tmp_u16 |= ((u32)b & 0x0000003F); + tmp_u16 |= (((u32)a & 0x0000003F) << 6); bcm43xx_phy_write(bcm, 0x048A, tmp_u16); } break; -- cgit v1.2.3 From 72fb851e971a416f47ad0a3ffca7342a424af37a Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 22 Mar 2006 18:10:19 +0100 Subject: [PATCH] bcm43xx: add useless and broken statistics stuff. People seem to want it. well... Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 2 ++ drivers/net/wireless/bcm43xx/bcm43xx_main.c | 3 ++ drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 52 ++++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 57fcaafcf7d..ae0fe5cf1d4 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -621,6 +621,8 @@ struct bcm43xx_noise_calculation { struct bcm43xx_stats { u8 link_quality; + u8 noise; + struct iw_statistics wstats; /* Store the last TX/RX times here for updating the leds. */ unsigned long last_tx; unsigned long last_rx; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index e680d2acc44..15deaa508e5 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -1539,6 +1539,7 @@ static void handle_irq_noise(struct bcm43xx_private *bcm) average *= 125; average += 64; average /= 128; + tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C); tmp = (tmp / 128) & 0x1F; if (tmp >= 8) @@ -1550,6 +1551,8 @@ static void handle_irq_noise(struct bcm43xx_private *bcm) else average -= 48; +/* FIXME: This is wrong, but people want fancy stats. well... */ +bcm->stats.noise = average; if (average > -65) bcm->stats.link_quality = 0; else if (average > -75) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index 651ba605495..e9296340285 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -244,13 +244,13 @@ static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, range->max_qual.qual = 100; /* TODO: Real max RSSI */ - range->max_qual.level = 0; - range->max_qual.noise = 0; + range->max_qual.level = 3; + range->max_qual.noise = 100; range->max_qual.updated = 7; range->avg_qual.qual = 70; - range->avg_qual.level = 0; - range->avg_qual.noise = 0; + range->avg_qual.level = 2; + range->avg_qual.noise = 40; range->avg_qual.updated = 7; range->min_rts = BCM43xx_MIN_RTS_THRESHOLD; @@ -875,6 +875,49 @@ out: return err; } +/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */ + +static struct iw_statistics *bcm43xx_get_wireless_stats(struct net_device *net_dev) +{ + struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct ieee80211softmac_device *mac = ieee80211_priv(net_dev); + struct iw_statistics *wstats; + + wstats = &bcm->stats.wstats; + if (!mac->associated) { + wstats->miss.beacon = 0; +// bcm->ieee->ieee_stats.tx_retry_limit_exceeded = 0; // FIXME: should this be cleared here? + wstats->discard.retries = 0; +// bcm->ieee->ieee_stats.tx_discards_wrong_sa = 0; // FIXME: same question + wstats->discard.nwid = 0; +// bcm->ieee->ieee_stats.rx_discards_undecryptable = 0; // FIXME: ditto + wstats->discard.code = 0; +// bcm->ieee->ieee_stats.rx_fragments = 0; // FIXME: same here + wstats->discard.fragment = 0; + wstats->discard.misc = 0; + wstats->qual.qual = 0; + wstats->qual.level = 0; + wstats->qual.noise = 0; + wstats->qual.updated = 7; + wstats->qual.updated |= IW_QUAL_NOISE_INVALID | + IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; + return wstats; + } + /* fill in the real statistics when iface associated */ + wstats->qual.qual = 100; // TODO: get the real signal quality + wstats->qual.level = 3 - bcm->stats.link_quality; + wstats->qual.noise = bcm->stats.noise; + wstats->qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED | + IW_QUAL_NOISE_UPDATED; + wstats->discard.code = bcm->ieee->ieee_stats.rx_discards_undecryptable; + wstats->discard.retries = bcm->ieee->ieee_stats.tx_retry_limit_exceeded; + wstats->discard.nwid = bcm->ieee->ieee_stats.tx_discards_wrong_sa; + wstats->discard.fragment = bcm->ieee->ieee_stats.rx_fragments; + wstats->discard.misc = 0; // FIXME + wstats->miss.beacon = 0; // FIXME + return wstats; +} + #ifdef WX # undef WX @@ -1010,6 +1053,7 @@ const struct iw_handler_def bcm43xx_wx_handlers_def = { .num_private_args = ARRAY_SIZE(bcm43xx_priv_wx_args), .private = bcm43xx_priv_wx_handlers, .private_args = bcm43xx_priv_wx_args, + .get_wireless_stats = bcm43xx_get_wireless_stats, }; /* vim: set ts=8 sw=8 sts=8: */ -- cgit v1.2.3 From 04b98f71e2e3facc15e73b7e3ae9516ecb737375 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 25 Mar 2006 15:37:53 +0100 Subject: [PATCH] bcm43xx: get rid of "/* vim: ..." lines at the end of several files. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_leds.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_pio.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 2 -- drivers/net/wireless/bcm43xx/bcm43xx_xmit.c | 2 -- 8 files changed, 16 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c index f73d36b8e0f..d2c3401e9b7 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c @@ -497,5 +497,3 @@ void bcm43xx_printk_bitdump(const unsigned char *data, } printk("\n"); } - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index 9c64438b767..18928acedd7 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -968,5 +968,3 @@ void bcm43xx_dma_tx_resume(struct bcm43xx_dmaring *ring) & ~BCM43xx_DMA_TXCTRL_SUSPEND); bcm43xx_power_saving_ctl_bits(ring->bcm, -1, -1); } - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c index c8f5ad75d2a..4b2c02c0b31 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_leds.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_leds.c @@ -291,5 +291,3 @@ void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on) } bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl); } - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 15deaa508e5..281db642bd5 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3956,5 +3956,3 @@ static void __exit bcm43xx_exit(void) module_init(bcm43xx_init) module_exit(bcm43xx_exit) - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c index 5b6f0a84d01..c59ddd40680 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_pio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_pio.c @@ -604,5 +604,3 @@ data_ready: } bcm43xx_rx(queue->bcm, skb, rxhdr); } - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c index 35c3c9704c3..c44d890b949 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_sysfs.c @@ -320,5 +320,3 @@ void bcm43xx_sysfs_unregister(struct bcm43xx_private *bcm) device_remove_file(dev, &sysfs->attr_interfmode); device_remove_file(dev, &sysfs->attr_sprom); } - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index e9296340285..e72be32bda7 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -1055,5 +1055,3 @@ const struct iw_handler_def bcm43xx_wx_handlers_def = { .private_args = bcm43xx_priv_wx_args, .get_wireless_stats = bcm43xx_get_wireless_stats, }; - -/* vim: set ts=8 sw=8 sts=8: */ diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c index c4809da8e9c..9c37478c80d 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c @@ -577,5 +577,3 @@ int bcm43xx_rx(struct bcm43xx_private *bcm, return err; } - -/* vim: set ts=8 sw=8 sts=8: */ -- cgit v1.2.3 From d1ca6c4ff6714826acb1a434e5d3862984eb26d5 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 25 Mar 2006 15:43:18 +0100 Subject: [PATCH] bcm43xx: fix "include" issues on some platforms. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 3 +-- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index 18928acedd7..bad5374b81b 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -34,11 +34,10 @@ #include "bcm43xx_power.h" #include "bcm43xx_xmit.h" -#include +#include #include #include #include -#include static inline int free_slots(struct bcm43xx_dmaring *ring) diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 281db642bd5..29df4f844c9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include "bcm43xx.h" -- cgit v1.2.3 From b5e868edbeaa5fd832d42563195c0da00edfd3c9 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 25 Mar 2006 16:27:32 +0100 Subject: [PATCH] bcm43xx: remove some compilerwarnings. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_dma.c | 1 - drivers/net/wireless/bcm43xx/bcm43xx_main.c | 10 ++++-- drivers/net/wireless/bcm43xx/bcm43xx_wx.c | 55 ----------------------------- drivers/net/wireless/bcm43xx/bcm43xx_xmit.c | 7 ++-- 4 files changed, 13 insertions(+), 60 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c index bad5374b81b..c3681b8f09b 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_dma.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_dma.c @@ -787,7 +787,6 @@ int bcm43xx_dma_tx(struct bcm43xx_private *bcm, void bcm43xx_dma_handle_xmitstatus(struct bcm43xx_private *bcm, struct bcm43xx_xmitstatus *status) { - struct bcm43xx_dma *dma = bcm43xx_current_dma(bcm); struct bcm43xx_dmaring *ring; struct bcm43xx_dmadesc *desc; struct bcm43xx_dmadesc_meta *meta; diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 29df4f844c9..ac9a8dd1ab8 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -404,6 +404,8 @@ static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm) bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i))); } +//FIXME: Well, we should probably call them from somewhere. +#if 0 static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time) { /* slot_time is in usec. */ @@ -422,8 +424,12 @@ static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm) { bcm43xx_set_slot_time(bcm, 20); } +#endif -//FIXME: rename this func? +/* FIXME: To get the MAC-filter working, we need to implement the + * following functions (and rename them :) + */ +#if 0 static void bcm43xx_disassociate(struct bcm43xx_private *bcm) { bcm43xx_mac_suspend(bcm); @@ -451,7 +457,6 @@ static void bcm43xx_disassociate(struct bcm43xx_private *bcm) bcm43xx_mac_enable(bcm); } -//FIXME: rename this func? static void bcm43xx_associate(struct bcm43xx_private *bcm, const u8 *mac) { @@ -462,6 +467,7 @@ static void bcm43xx_associate(struct bcm43xx_private *bcm, bcm43xx_write_mac_bssid_templates(bcm); bcm43xx_mac_enable(bcm); } +#endif /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. * Returns the _previously_ enabled IRQ mask. diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c index e72be32bda7..3daee828ef4 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c @@ -106,7 +106,6 @@ static int bcm43xx_wx_set_channelfreq(struct net_device *net_dev, char *extra) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); - struct ieee80211softmac_device *softmac = bcm->softmac; unsigned long flags; u8 channel; int freq; @@ -205,24 +204,6 @@ static int bcm43xx_wx_get_mode(struct net_device *net_dev, return 0; } -static int bcm43xx_wx_set_sensitivity(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - /*TODO*/ - return 0; -} - -static int bcm43xx_wx_get_sensitivity(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - /*TODO*/ - return 0; -} - static int bcm43xx_wx_get_rangeparams(struct net_device *net_dev, struct iw_request_info *info, union iwreq_data *data, @@ -517,24 +498,6 @@ out_unlock: return err; } -static int bcm43xx_wx_set_retry(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - /*TODO*/ - return 0; -} - -static int bcm43xx_wx_get_retry(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - /*TODO*/ - return 0; -} - static int bcm43xx_wx_set_encoding(struct net_device *net_dev, struct iw_request_info *info, union iwreq_data *data, @@ -587,24 +550,6 @@ static int bcm43xx_wx_get_encodingext(struct net_device *net_dev, return err; } -static int bcm43xx_wx_set_power(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - /*TODO*/ - return 0; -} - -static int bcm43xx_wx_get_power(struct net_device *net_dev, - struct iw_request_info *info, - union iwreq_data *data, - char *extra) -{ - /*TODO*/ - return 0; -} - static int bcm43xx_wx_set_interfmode(struct net_device *net_dev, struct iw_request_info *info, union iwreq_data *data, diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c index 9c37478c80d..d8ece28c079 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c @@ -215,7 +215,7 @@ static void bcm43xx_generate_rts(const struct bcm43xx_phyinfo *phy, u8 fallback_bitrate; int ofdm_modulation; int fallback_ofdm_modulation; - u8 *sa, *da; +// u8 *sa, *da; u16 flen; //FIXME sa = ieee80211_get_SA((struct ieee80211_hdr *)wlhdr); @@ -267,7 +267,7 @@ assert(dur); //printk(BCM43xx_MACFMT " " BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(wlhdr->addr1), BCM43xx_MACARG(wlhdr->addr2), BCM43xx_MACARG(wlhdr->addr3)); //printk(BCM43xx_MACFMT " " BCM43xx_MACFMT "\n", BCM43xx_MACARG(sa), BCM43xx_MACARG(da)); memcpy(txhdr->rts_cts_mac1, wlhdr->addr1, ETH_ALEN);//FIXME! - memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN); +// memcpy(txhdr->rts_cts_mac2, sa, ETH_ALEN); *flags |= BCM43xx_TXHDRFLAG_RTSCTS; *flags |= BCM43xx_TXHDRFLAG_RTS; @@ -439,6 +439,8 @@ static s8 bcm43xx_rssi_postprocess(struct bcm43xx_private *bcm, return (s8)tmp; } +//TODO +#if 0 static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, u8 in_rssi) { @@ -453,6 +455,7 @@ static s8 bcm43xx_rssinoise_postprocess(struct bcm43xx_private *bcm, return ret; } +#endif int bcm43xx_rx(struct bcm43xx_private *bcm, struct sk_buff *skb, -- cgit v1.2.3 From 8afceb1e6a3b6361c7c2456ef488ee9c6db7b370 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 25 Mar 2006 17:04:41 +0100 Subject: [PATCH] bcm43xx: fix the remaining sparse warnings. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 ++-- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index ac9a8dd1ab8..7c1d72fc628 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -2509,7 +2509,7 @@ error: return -ENODEV; } -void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) +static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) { /* Initialize a "phyinfo" structure. The structure is already * zeroed out. @@ -2521,7 +2521,7 @@ void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy) spin_lock_init(&phy->lock); } -void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio) +static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio) { /* Initialize a "radioinfo" structure. The structure is already * zeroed out. diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 054c64e462f..4ab17a7f7e9 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -1057,9 +1057,14 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) bcm43xx_phy_write(bcm, 0x002F, 0x0202); } - if ((bcm->sprom.boardflags & BCM43xx_BFL_RSSI) == 0) { - FIXME();//FIXME: 0x7FFFFFFF should be 16-bit ! - bcm43xx_nrssi_hw_update(bcm, (u16)0x7FFFFFFF); + if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) { + /* The specs state to update the NRSSI LT with + * the value 0x7FFFFFFF here. I think that is some weird + * compiler optimization in the original driver. + * Essentially, what we do here is resetting all NRSSI LT + * entries to -32 (see the limit_value() in nrssi_hw_update()) + */ + bcm43xx_nrssi_hw_update(bcm, 0xFFFF); bcm43xx_calc_nrssi_threshold(bcm); } else if (phy->connected) { if (radio->nrssi[0] == -1000) { -- cgit v1.2.3 From adc40e9796d03d56e99bdac62492492a1098124b Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Sat, 25 Mar 2006 20:36:57 +0100 Subject: [PATCH] bcm43xx: sync GPHY init with the specs. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx.h | 5 + drivers/net/wireless/bcm43xx/bcm43xx_main.c | 4 +- drivers/net/wireless/bcm43xx/bcm43xx_phy.c | 275 +++++++++++++++++++++++++--- 3 files changed, 255 insertions(+), 29 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index ae0fe5cf1d4..dcadd295de4 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h @@ -495,6 +495,10 @@ struct bcm43xx_phyinfo { const s8 *tssi2dbm; /* idle TSSI value */ s8 idle_tssi; + + /* Values from bcm43xx_calc_loopback_gain() */ + u16 loopback_gain[2]; + /* PHY lock for core.rev < 3 * This lock is only used by bcm43xx_phy_{un}lock() */ @@ -674,6 +678,7 @@ struct bcm43xx_private { u16 chip_id; u8 chip_rev; + u8 chip_package; struct bcm43xx_sprominfo sprom; #define BCM43xx_NR_LEDS 4 diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 7c1d72fc628..2b7ef9b46cc 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -570,6 +570,7 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm) radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm); radio->radio_atten = bcm43xx_default_radio_attenuation(bcm); radio->txctl1 = bcm43xx_default_txctl1(bcm); + radio->txctl2 = 0xFFFF; if (phy->type == BCM43xx_PHYTYPE_A) radio->txpower_desired = bcm->sprom.maxpower_aphy; else @@ -2635,7 +2636,8 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm) } bcm->chip_id = chip_id_16; - bcm->chip_rev = (chip_id_32 & 0x000f0000) >> 16; + bcm->chip_rev = (chip_id_32 & 0x000F0000) >> 16; + bcm->chip_package = (chip_id_32 & 0x00F00000) >> 20; dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n", bcm->chip_id, bcm->chip_rev); diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 4ab17a7f7e9..0a66f43ca0c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c @@ -994,12 +994,205 @@ static void bcm43xx_phy_initb6(struct bcm43xx_private *bcm) bcm43xx_write16(bcm, 0x03E6, 0x0); } +static void bcm43xx_calc_loopback_gain(struct bcm43xx_private *bcm) +{ + struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); + struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); + u16 backup_phy[15]; + u16 backup_radio[3]; + u16 backup_bband; + u16 i; + u16 loop1_cnt, loop1_done, loop1_omitted; + u16 loop2_done; + + backup_phy[0] = bcm43xx_phy_read(bcm, 0x0429); + backup_phy[1] = bcm43xx_phy_read(bcm, 0x0001); + backup_phy[2] = bcm43xx_phy_read(bcm, 0x0811); + backup_phy[3] = bcm43xx_phy_read(bcm, 0x0812); + backup_phy[4] = bcm43xx_phy_read(bcm, 0x0814); + backup_phy[5] = bcm43xx_phy_read(bcm, 0x0815); + backup_phy[6] = bcm43xx_phy_read(bcm, 0x005A); + backup_phy[7] = bcm43xx_phy_read(bcm, 0x0059); + backup_phy[8] = bcm43xx_phy_read(bcm, 0x0058); + backup_phy[9] = bcm43xx_phy_read(bcm, 0x000A); + backup_phy[10] = bcm43xx_phy_read(bcm, 0x0003); + backup_phy[11] = bcm43xx_phy_read(bcm, 0x080F); + backup_phy[12] = bcm43xx_phy_read(bcm, 0x0810); + backup_phy[13] = bcm43xx_phy_read(bcm, 0x002B); + backup_phy[14] = bcm43xx_phy_read(bcm, 0x0015); + bcm43xx_phy_read(bcm, 0x002D); /* dummy read */ + backup_bband = radio->baseband_atten; + backup_radio[0] = bcm43xx_radio_read16(bcm, 0x0052); + backup_radio[1] = bcm43xx_radio_read16(bcm, 0x0043); + backup_radio[2] = bcm43xx_radio_read16(bcm, 0x007A); + + bcm43xx_phy_write(bcm, 0x0429, + bcm43xx_phy_read(bcm, 0x0429) & 0x3FFF); + bcm43xx_phy_write(bcm, 0x0001, + bcm43xx_phy_read(bcm, 0x0001) & 0x8000); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x0002); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) & 0xFFFD); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x0001); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) & 0xFFFE); + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0001); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFE); + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0002); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFD); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x000C); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) | 0x000C); + + bcm43xx_phy_write(bcm, 0x0811, + (bcm43xx_phy_read(bcm, 0x0811) + & 0xFFCF) | 0x0030); + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) + & 0xFFCF) | 0x0010); + + bcm43xx_phy_write(bcm, 0x005A, 0x0780); + bcm43xx_phy_write(bcm, 0x0059, 0xC810); + bcm43xx_phy_write(bcm, 0x0058, 0x000D); + if (phy->version == 0) { + bcm43xx_phy_write(bcm, 0x0003, 0x0122); + } else { + bcm43xx_phy_write(bcm, 0x000A, + bcm43xx_phy_read(bcm, 0x000A) + | 0x2000); + } + bcm43xx_phy_write(bcm, 0x0814, + bcm43xx_phy_read(bcm, 0x0814) | 0x0004); + bcm43xx_phy_write(bcm, 0x0815, + bcm43xx_phy_read(bcm, 0x0815) & 0xFFFB); + bcm43xx_phy_write(bcm, 0x0003, + (bcm43xx_phy_read(bcm, 0x0003) + & 0xFF9F) | 0x0040); + if (radio->version == 0x2050 && radio->revision == 2) { + bcm43xx_radio_write16(bcm, 0x0052, 0x0000); + bcm43xx_radio_write16(bcm, 0x0043, + (bcm43xx_radio_read16(bcm, 0x0043) + & 0xFFF0) | 0x0009); + loop1_cnt = 9; + } else if (radio->revision == 8) { + bcm43xx_radio_write16(bcm, 0x0043, 0x000F); + loop1_cnt = 15; + } else + loop1_cnt = 0; + + bcm43xx_phy_set_baseband_attenuation(bcm, 11); + + if (phy->rev >= 3) + bcm43xx_phy_write(bcm, 0x080F, 0xC020); + else + bcm43xx_phy_write(bcm, 0x080F, 0x8020); + bcm43xx_phy_write(bcm, 0x0810, 0x0000); + + bcm43xx_phy_write(bcm, 0x002B, + (bcm43xx_phy_read(bcm, 0x002B) + & 0xFFC0) | 0x0001); + bcm43xx_phy_write(bcm, 0x002B, + (bcm43xx_phy_read(bcm, 0x002B) + & 0xC0FF) | 0x0800); + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) | 0x0100); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) & 0xCFFF); + if (bcm->sprom.boardflags & BCM43xx_BFL_EXTLNA) { + if (phy->rev >= 7) { + bcm43xx_phy_write(bcm, 0x0811, + bcm43xx_phy_read(bcm, 0x0811) + | 0x0800); + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) + | 0x8000); + } + } + bcm43xx_radio_write16(bcm, 0x007A, + bcm43xx_radio_read16(bcm, 0x007A) + & 0x00F7); + + for (i = 0; i < loop1_cnt; i++) { + bcm43xx_radio_write16(bcm, 0x0043, loop1_cnt); + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) + & 0xF0FF) | (i << 8)); + bcm43xx_phy_write(bcm, 0x0015, + (bcm43xx_phy_read(bcm, 0x0015) + & 0x0FFF) | 0xA000); + bcm43xx_phy_write(bcm, 0x0015, + (bcm43xx_phy_read(bcm, 0x0015) + & 0x0FFF) | 0xF000); + udelay(20); + if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC) + break; + } + loop1_done = i; + loop1_omitted = loop1_cnt - loop1_done; + + loop2_done = 0; + if (loop1_done >= 8) { + bcm43xx_phy_write(bcm, 0x0812, + bcm43xx_phy_read(bcm, 0x0812) + | 0x0030); + for (i = loop1_done - 8; i < 16; i++) { + bcm43xx_phy_write(bcm, 0x0812, + (bcm43xx_phy_read(bcm, 0x0812) + & 0xF0FF) | (i << 8)); + bcm43xx_phy_write(bcm, 0x0015, + (bcm43xx_phy_read(bcm, 0x0015) + & 0x0FFF) | 0xA000); + bcm43xx_phy_write(bcm, 0x0015, + (bcm43xx_phy_read(bcm, 0x0015) + & 0x0FFF) | 0xF000); + udelay(20); + if (bcm43xx_phy_read(bcm, 0x002D) >= 0x0DFC) + break; + } + } + + bcm43xx_phy_write(bcm, 0x0814, backup_phy[4]); + bcm43xx_phy_write(bcm, 0x0815, backup_phy[5]); + bcm43xx_phy_write(bcm, 0x005A, backup_phy[6]); + bcm43xx_phy_write(bcm, 0x0059, backup_phy[7]); + bcm43xx_phy_write(bcm, 0x0058, backup_phy[8]); + bcm43xx_phy_write(bcm, 0x000A, backup_phy[9]); + bcm43xx_phy_write(bcm, 0x0003, backup_phy[10]); + bcm43xx_phy_write(bcm, 0x080F, backup_phy[11]); + bcm43xx_phy_write(bcm, 0x0810, backup_phy[12]); + bcm43xx_phy_write(bcm, 0x002B, backup_phy[13]); + bcm43xx_phy_write(bcm, 0x0015, backup_phy[14]); + + bcm43xx_phy_set_baseband_attenuation(bcm, backup_bband); + + bcm43xx_radio_write16(bcm, 0x0052, backup_radio[0]); + bcm43xx_radio_write16(bcm, 0x0043, backup_radio[1]); + bcm43xx_radio_write16(bcm, 0x007A, backup_radio[2]); + + bcm43xx_phy_write(bcm, 0x0811, backup_phy[2] | 0x0003); + udelay(10); + bcm43xx_phy_write(bcm, 0x0811, backup_phy[2]); + bcm43xx_phy_write(bcm, 0x0812, backup_phy[3]); + bcm43xx_phy_write(bcm, 0x0429, backup_phy[0]); + bcm43xx_phy_write(bcm, 0x0001, backup_phy[1]); + + phy->loopback_gain[0] = ((loop1_done * 6) - (loop1_omitted * 4)) - 11; + phy->loopback_gain[1] = (24 - (3 * loop2_done)) * 2; +} + static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) { struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 tmp; - + if (phy->rev == 1) bcm43xx_phy_initb5(bcm); else if (phy->rev >= 2 && phy->rev <= 7) @@ -1015,47 +1208,63 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) else if (phy->rev >= 3) bcm43xx_phy_write(bcm, 0x0811, 0x0400); bcm43xx_phy_write(bcm, 0x0015, 0x00C0); - tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF; - if (tmp == 3) { - bcm43xx_phy_write(bcm, 0x04C2, 0x1816); - bcm43xx_phy_write(bcm, 0x04C3, 0x8606); - } else if (tmp == 4 || tmp == 5) { - bcm43xx_phy_write(bcm, 0x04C2, 0x1816); - bcm43xx_phy_write(bcm, 0x04C3, 0x8006); - bcm43xx_phy_write(bcm, 0x04CC, (bcm43xx_phy_read(bcm, 0x04CC) - & 0x00FF) | 0x1F00); + if (phy->connected) { + tmp = bcm43xx_phy_read(bcm, 0x0400) & 0xFF; + if (tmp < 6) { + bcm43xx_phy_write(bcm, 0x04C2, 0x1816); + bcm43xx_phy_write(bcm, 0x04C3, 0x8006); + if (tmp != 3) { + bcm43xx_phy_write(bcm, 0x04CC, + (bcm43xx_phy_read(bcm, 0x04CC) + & 0x00FF) | 0x1F00); + } + } } } - if (radio->revision <= 3 && phy->connected) + if (phy->rev < 3 && phy->connected) bcm43xx_phy_write(bcm, 0x047E, 0x0078); - if (radio->revision >= 6 && radio->revision <= 8) { + if (phy->rev >= 6 && phy->rev <= 8) { bcm43xx_phy_write(bcm, 0x0801, bcm43xx_phy_read(bcm, 0x0801) | 0x0080); bcm43xx_phy_write(bcm, 0x043E, bcm43xx_phy_read(bcm, 0x043E) | 0x0004); } - if (radio->initval == 0xFFFF) { - radio->initval = bcm43xx_radio_init2050(bcm); + if (phy->rev >= 2 && phy->connected) + bcm43xx_calc_loopback_gain(bcm); + if (radio->revision != 8) { + if (radio->initval == 0xFFFF) + radio->initval = bcm43xx_radio_init2050(bcm); + else + bcm43xx_radio_write16(bcm, 0x0078, radio->initval); + } + if (radio->txctl2 == 0xFFFF) { bcm43xx_phy_lo_g_measure(bcm); } else { - bcm43xx_radio_write16(bcm, 0x0078, radio->initval); - bcm43xx_radio_write16(bcm, 0x0052, - (bcm43xx_radio_read16(bcm, 0x0052) & 0xFFF0) - | radio->txctl2); - } - - if (phy->connected) { - bcm43xx_phy_lo_adjust(bcm, 0); - bcm43xx_phy_write(bcm, 0x080F, 0x8078); - + if (radio->version == 0x2050 && radio->revision == 8) { + //FIXME + } else { + bcm43xx_radio_write16(bcm, 0x0052, + (bcm43xx_radio_read16(bcm, 0x0052) + & 0xFFF0) | radio->txctl1); + } + if (phy->rev >= 6) { + /* + bcm43xx_phy_write(bcm, 0x0036, + (bcm43xx_phy_read(bcm, 0x0036) + & 0xF000) | (FIXME << 12)); + */ + } if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) - bcm43xx_phy_write(bcm, 0x002E, 0x807F); - else bcm43xx_phy_write(bcm, 0x002E, 0x8075); - + else + bcm43xx_phy_write(bcm, 0x003E, 0x807F); if (phy->rev < 2) bcm43xx_phy_write(bcm, 0x002F, 0x0101); else bcm43xx_phy_write(bcm, 0x002F, 0x0202); } + if (phy->connected) { + bcm43xx_phy_lo_adjust(bcm, 0); + bcm43xx_phy_write(bcm, 0x080F, 0x8078); + } if (!(bcm->sprom.boardflags & BCM43xx_BFL_RSSI)) { /* The specs state to update the NRSSI LT with @@ -1070,10 +1279,20 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm) if (radio->nrssi[0] == -1000) { assert(radio->nrssi[1] == -1000); bcm43xx_calc_nrssi_slope(bcm); - } else + } else { + assert(radio->nrssi[1] != -1000); bcm43xx_calc_nrssi_threshold(bcm); + } } + if (radio->revision == 8) + bcm43xx_phy_write(bcm, 0x0805, 0x3230); bcm43xx_phy_init_pctl(bcm); + if (bcm->chip_id == 0x4306 && bcm->chip_package != 2) { + bcm43xx_phy_write(bcm, 0x0429, + bcm43xx_phy_read(bcm, 0x0429) & 0xBFFF); + bcm43xx_phy_write(bcm, 0x04C3, + bcm43xx_phy_read(bcm, 0x04C3) & 0x7FFF); + } } static u16 bcm43xx_phy_lo_b_r15_loop(struct bcm43xx_private *bcm) -- cgit v1.2.3 From ec483781fe98bba92e00f4428f8d69dd5e071246 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Mon, 27 Mar 2006 11:49:51 +0200 Subject: [PATCH] bcm43xx: don't set the channel on a device, which is down. Initial patch by David Woodhouse and Michael Marineau. Locking fix by me. Signed-off-by: Michael Buesch Signed-off-by: John W. Linville --- drivers/net/wireless/bcm43xx/bcm43xx_main.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index 2b7ef9b46cc..c37371fc9e0 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c @@ -3530,12 +3530,18 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev, u8 channel) { struct bcm43xx_private *bcm = bcm43xx_priv(net_dev); + struct bcm43xx_radioinfo *radio; unsigned long flags; bcm43xx_lock_mmio(bcm, flags); - bcm43xx_mac_suspend(bcm); - bcm43xx_radio_selectchannel(bcm, channel, 0); - bcm43xx_mac_enable(bcm); + if (bcm->initialized) { + bcm43xx_mac_suspend(bcm); + bcm43xx_radio_selectchannel(bcm, channel, 0); + bcm43xx_mac_enable(bcm); + } else { + radio = bcm43xx_current_radio(bcm); + radio->initial_channel = channel; + } bcm43xx_unlock_mmio(bcm, flags); } -- cgit v1.2.3 From e4a9af98bb0fab13be6e3adbe108d565b790158a Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 24 Mar 2006 17:56:19 +0100 Subject: [PATCH] PCMCIA_SPECTRUM must select FW_LOADER PCMCIA_SPECTRUM must select FW_LOADER. Reported by "Alexander E. Patrakov" . Signed-off-by: Adrian Bunk Signed-off-by: John W. Linville --- drivers/net/wireless/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/net') diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 9c01fb26c8f..f85e3019000 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -404,6 +404,7 @@ config PCMCIA_HERMES config PCMCIA_SPECTRUM tristate "Symbol Spectrum24 Trilogy PCMCIA card support" depends on NET_RADIO && PCMCIA && HERMES + select FW_LOADER ---help--- This is a driver for 802.11b cards using RAM-loadable Symbol -- cgit v1.2.3 From 79058acaf5b6d4bcc3056382619de3ca9cebc62f Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 24 Mar 2006 21:24:54 -0800 Subject: [PATCH] hostap: Make hostap_tx_encrypt() static hostap_tx_encrypt() is used only inside hostap_80211_tx.c and there are no plans to use it elsewhere in the future either, so let's make it static. As a bonus, this should silence Coverity scanner from complaining about bogus FORWARD_NULL case (CID: 274). Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_80211.h | 2 -- drivers/net/wireless/hostap/hostap_80211_tx.c | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h index 1fc72fe511e..cc1ee7f4f5f 100644 --- a/drivers/net/wireless/hostap/hostap_80211.h +++ b/drivers/net/wireless/hostap/hostap_80211.h @@ -92,8 +92,6 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, void hostap_dump_tx_80211(const char *name, struct sk_buff *skb); int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev); int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev); -struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, - struct ieee80211_crypt_data *crypt); int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev); #endif /* HOSTAP_80211_H */ diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 4a85e63906f..a881212e1fa 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -299,8 +299,8 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Called only from software IRQ */ -struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, - struct ieee80211_crypt_data *crypt) +static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, + struct ieee80211_crypt_data *crypt) { struct hostap_interface *iface; local_info_t *local; @@ -317,7 +317,7 @@ struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, } if (local->tkip_countermeasures && - crypt && crypt->ops && strcmp(crypt->ops->name, "TKIP") == 0) { + strcmp(crypt->ops->name, "TKIP") == 0) { hdr = (struct ieee80211_hdr_4addr *) skb->data; if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " @@ -535,5 +535,4 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) EXPORT_SYMBOL(hostap_dump_tx_80211); -EXPORT_SYMBOL(hostap_tx_encrypt); EXPORT_SYMBOL(hostap_master_start_xmit); -- cgit v1.2.3 From cfa146e4be274fd04bfdb26b3c96cdfe81a43dc2 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Fri, 24 Mar 2006 21:24:55 -0800 Subject: [PATCH] hostap: Fix EAPOL frame encryption Fixed encrypted of EAPOL frames from wlan#ap interface (hostapd). This was broken when moving to use new frame control field defines in net/ieee80211.h. hostapd uses Protected flag, not protocol version (which was cleared in this function anyway). This fixes WPA group key handshake and re-authentication. http://hostap.epitest.fi/bugz/show_bug.cgi?id=126 Signed-off-by: Jouni Malinen Signed-off-by: John W. Linville --- drivers/net/wireless/hostap/hostap_80211_tx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index a881212e1fa..06a5214145e 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -469,7 +469,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) } if (local->ieee_802_1x && meta->ethertype == ETH_P_PAE && tx.crypt && - !(fc & IEEE80211_FCTL_VERS)) { + !(fc & IEEE80211_FCTL_PROTECTED)) { no_encrypt = 1; PDEBUG(DEBUG_EXTRA2, "%s: TX: IEEE 802.1X - passing " "unencrypted EAPOL frame\n", dev->name); -- cgit v1.2.3 From e041c683412d5bf44dc2b109053e3b837b71742d Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 27 Mar 2006 01:16:30 -0800 Subject: [PATCH] Notifier chain update: API changes The kernel's implementation of notifier chains is unsafe. There is no protection against entries being added to or removed from a chain while the chain is in use. The issues were discussed in this thread: http://marc.theaimsgroup.com/?l=linux-kernel&m=113018709002036&w=2 We noticed that notifier chains in the kernel fall into two basic usage classes: "Blocking" chains are always called from a process context and the callout routines are allowed to sleep; "Atomic" chains can be called from an atomic context and the callout routines are not allowed to sleep. We decided to codify this distinction and make it part of the API. Therefore this set of patches introduces three new, parallel APIs: one for blocking notifiers, one for atomic notifiers, and one for "raw" notifiers (which is really just the old API under a new name). New kinds of data structures are used for the heads of the chains, and new routines are defined for registration, unregistration, and calling a chain. The three APIs are explained in include/linux/notifier.h and their implementation is in kernel/sys.c. With atomic and blocking chains, the implementation guarantees that the chain links will not be corrupted and that chain callers will not get messed up by entries being added or removed. For raw chains the implementation provides no guarantees at all; users of this API must provide their own protections. (The idea was that situations may come up where the assumptions of the atomic and blocking APIs are not appropriate, so it should be possible for users to handle these things in their own way.) There are some limitations, which should not be too hard to live with. For atomic/blocking chains, registration and unregistration must always be done in a process context since the chain is protected by a mutex/rwsem. Also, a callout routine for a non-raw chain must not try to register or unregister entries on its own chain. (This did happen in a couple of places and the code had to be changed to avoid it.) Since atomic chains may be called from within an NMI handler, they cannot use spinlocks for synchronization. Instead we use RCU. The overhead falls almost entirely in the unregister routine, which is okay since unregistration is much less frequent that calling a chain. Here is the list of chains that we adjusted and their classifications. None of them use the raw API, so for the moment it is only a placeholder. ATOMIC CHAINS ------------- arch/i386/kernel/traps.c: i386die_chain arch/ia64/kernel/traps.c: ia64die_chain arch/powerpc/kernel/traps.c: powerpc_die_chain arch/sparc64/kernel/traps.c: sparc64die_chain arch/x86_64/kernel/traps.c: die_chain drivers/char/ipmi/ipmi_si_intf.c: xaction_notifier_list kernel/panic.c: panic_notifier_list kernel/profile.c: task_free_notifier net/bluetooth/hci_core.c: hci_notifier net/ipv4/netfilter/ip_conntrack_core.c: ip_conntrack_chain net/ipv4/netfilter/ip_conntrack_core.c: ip_conntrack_expect_chain net/ipv6/addrconf.c: inet6addr_chain net/netfilter/nf_conntrack_core.c: nf_conntrack_chain net/netfilter/nf_conntrack_core.c: nf_conntrack_expect_chain net/netlink/af_netlink.c: netlink_chain BLOCKING CHAINS --------------- arch/powerpc/platforms/pseries/reconfig.c: pSeries_reconfig_chain arch/s390/kernel/process.c: idle_chain arch/x86_64/kernel/process.c idle_notifier drivers/base/memory.c: memory_chain drivers/cpufreq/cpufreq.c cpufreq_policy_notifier_list drivers/cpufreq/cpufreq.c cpufreq_transition_notifier_list drivers/macintosh/adb.c: adb_client_list drivers/macintosh/via-pmu.c sleep_notifier_list drivers/macintosh/via-pmu68k.c sleep_notifier_list drivers/macintosh/windfarm_core.c wf_client_list drivers/usb/core/notify.c usb_notifier_list drivers/video/fbmem.c fb_notifier_list kernel/cpu.c cpu_chain kernel/module.c module_notify_list kernel/profile.c munmap_notifier kernel/profile.c task_exit_notifier kernel/sys.c reboot_notifier_list net/core/dev.c netdev_chain net/decnet/dn_dev.c: dnaddr_chain net/ipv4/devinet.c: inetaddr_chain It's possible that some of these classifications are wrong. If they are, please let us know or submit a patch to fix them. Note that any chain that gets called very frequently should be atomic, because the rwsem read-locking used for blocking chains is very likely to incur cache misses on SMP systems. (However, if the chain's callout routines may sleep then the chain cannot be atomic.) The patch set was written by Alan Stern and Chandra Seetharaman, incorporating material written by Keith Owens and suggestions from Paul McKenney and Andrew Morton. [jes@sgi.com: restructure the notifier chain initialization macros] Signed-off-by: Alan Stern Signed-off-by: Chandra Seetharaman Signed-off-by: Jes Sorensen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/bonding/bond_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 2d0ac169a86..f13a539dc16 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3159,7 +3159,7 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave * bond_netdev_event: handle netdev notifier chain events. * * This function receives events for the netdev chain. The caller (an - * ioctl handler calling notifier_call_chain) holds the necessary + * ioctl handler calling blocking_notifier_call_chain) holds the necessary * locks for us to safely manipulate the slave devices (RTNL lock, * dev_probe_lock). */ -- cgit v1.2.3 From 803d0abb3dcfc93701c8a8dc7f2968a47271214c Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 27 Mar 2006 01:17:06 -0800 Subject: [PATCH] pnp: IRDA: adjust pnp_register_driver signature Remove the assumption that pnp_register_driver() returns the number of devices claimed. Signed-off-by: Bjorn Helgaas Cc: Adam Belay Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/irda/nsc-ircc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 83141a3ff54..9aa074b44dd 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -207,7 +207,7 @@ static int __init nsc_ircc_init(void) /* Register with PnP subsystem to detect disable ports */ ret = pnp_register_driver(&nsc_ircc_pnp_driver); - if (ret >= 0) + if (!ret) pnp_registered = 1; ret = -ENODEV; -- cgit v1.2.3 From e8222502ee6157e2713da9e0792c21f4ad458d50 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 28 Mar 2006 23:15:54 +1100 Subject: [PATCH] powerpc: Kill _machine and hard-coded platform numbers This removes statically assigned platform numbers and reworks the powerpc platform probe code to use a better mechanism. With this, board support files can simply declare a new machine type with a macro, and implement a probe() function that uses the flattened device-tree to detect if they apply for a given machine. We now have a machine_is() macro that replaces the comparisons of _machine with the various PLATFORM_* constants. This commit also changes various drivers to use the new macro instead of looking at _machine. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- drivers/net/tulip/de4x5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index ee48bfd6734..46d087c5467 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -4160,7 +4160,7 @@ get_hw_addr(struct net_device *dev) ** If the address starts with 00 a0, we have to bit-reverse ** each byte of the address. */ - if ( (_machine & _MACH_Pmac) && + if ( machine_is(powermac) && (dev->dev_addr[0] == 0) && (dev->dev_addr[1] == 0xa0) ) { -- cgit v1.2.3 From 0fed48463fb20c6bcabc5cf70e2de47b30507ee1 Mon Sep 17 00:00:00 2001 From: KAMEZAWA Hiroyuki Date: Tue, 28 Mar 2006 01:56:37 -0800 Subject: [PATCH] for_each_possible_cpu: loopback device. This patch replaces for_each_cpu with for_each_possible_cpu. Signed-off-by: KAMEZAWA Hiroyuki Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/loopback.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 0c13795dca3..b79d6e8d304 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -172,7 +172,7 @@ static struct net_device_stats *get_stats(struct net_device *dev) memset(stats, 0, sizeof(struct net_device_stats)); - for_each_cpu(i) { + for_each_possible_cpu(i) { struct net_device_stats *lb_stats; lb_stats = &per_cpu(loopback_stats, i); -- cgit v1.2.3 From 910638ae7ed4be27d6af55f6c9b5bf54b838e78b Mon Sep 17 00:00:00 2001 From: Matthias Gehre Date: Tue, 28 Mar 2006 01:56:48 -0800 Subject: [PATCH] Replace 0xff.. with correct DMA_xBIT_MASK Replace all occurences of 0xff.. in calls to function pci_set_dma_mask() and pci_set_consistant_dma_mask() with the corresponding DMA_xBIT_MASK from linux/dma-mapping.h. Signed-off-by: Matthias Gehre Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/forcedeth.c | 3 ++- drivers/net/ioc3-eth.c | 7 ++++--- drivers/net/ns83820.c | 6 +++--- drivers/net/wan/wanxl.c | 4 ++-- drivers/net/wireless/prism54/islpci_hotplug.c | 3 ++- 5 files changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index e7fc28b07e5..7627a75f4f7 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -134,6 +134,7 @@ #include #include #include +#include #include #include @@ -2932,7 +2933,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (id->driver_data & DEV_HAS_HIGH_DMA) { /* packet format 3: supports 40-bit addressing */ np->desc_ver = DESC_VER_3; - if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) { + if (pci_set_dma_mask(pci_dev, DMA_39BIT_MASK)) { printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n", pci_name(pci_dev)); } else { diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 9b8295ee06e..ae71ed57c12 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -44,6 +44,7 @@ #include #include #include +#include #ifdef CONFIG_SERIAL_8250 #include @@ -1195,17 +1196,17 @@ static int ioc3_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int err, pci_using_dac; /* Configure DMA attributes. */ - err = pci_set_dma_mask(pdev, 0xffffffffffffffffULL); + err = pci_set_dma_mask(pdev, DMA_64BIT_MASK); if (!err) { pci_using_dac = 1; - err = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL); + err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); if (err < 0) { printk(KERN_ERR "%s: Unable to obtain 64 bit DMA " "for consistent allocations\n", pci_name(pdev)); goto out; } } else { - err = pci_set_dma_mask(pdev, 0xffffffffULL); + err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (err) { printk(KERN_ERR "%s: No usable DMA configuration, " "aborting.\n", pci_name(pdev)); diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index 0fede50abd3..8e9b1a537de 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1828,10 +1828,10 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ int using_dac = 0; /* See if we can set the dma mask early on; failure is fatal. */ - if (sizeof(dma_addr_t) == 8 && - !pci_set_dma_mask(pci_dev, 0xffffffffffffffffULL)) { + if (sizeof(dma_addr_t) == 8 && + !pci_set_dma_mask(pci_dev, DMA_64BIT_MASK)) { using_dac = 1; - } else if (!pci_set_dma_mask(pci_dev, 0xffffffff)) { + } else if (!pci_set_dma_mask(pci_dev, DMA_32BIT_MASK)) { using_dac = 0; } else { printk(KERN_WARNING "ns83820.c: pci_set_dma_mask failed!\n"); diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index 9d3b51c3ef5..29a756dd979 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -577,8 +577,8 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev, We set both dma_mask and consistent_dma_mask to 28 bits and pray pci_alloc_consistent() will use this info. It should work on most platforms */ - if (pci_set_consistent_dma_mask(pdev, 0x0FFFFFFF) || - pci_set_dma_mask(pdev, 0x0FFFFFFF)) { + if (pci_set_consistent_dma_mask(pdev, DMA_28BIT_MASK) || + pci_set_dma_mask(pdev, DMA_28BIT_MASK)) { printk(KERN_ERR "wanXL: No usable DMA configuration\n"); return -EIO; } diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index b41d666fea3..bfa0cc319a0 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -22,6 +22,7 @@ #include #include #include /* For __init, __exit */ +#include #include "prismcompat.h" #include "islpci_dev.h" @@ -124,7 +125,7 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) } /* enable PCI DMA */ - if (pci_set_dma_mask(pdev, 0xffffffff)) { + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { printk(KERN_ERR "%s: 32-bit PCI DMA not supported", DRV_NAME); goto do_pci_disable_device; } -- cgit v1.2.3 From 7f927fcc2fd1575d01efb4b76665975007945690 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 28 Mar 2006 01:56:53 -0800 Subject: [PATCH] Typo fixes Fix a lot of typos. Eyeballed by jmc@ in OpenBSD. Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/irda/nsc-ircc.c | 2 +- drivers/net/sis900.c | 2 +- drivers/net/tulip/de4x5.c | 2 +- drivers/net/tulip/pnic2.c | 2 +- drivers/net/typhoon.c | 4 ++-- drivers/net/wireless/orinoco.c | 2 +- drivers/net/wireless/prism54/isl_ioctl.c | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 9aa074b44dd..cc7ff8f00e4 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -812,7 +812,7 @@ static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info) int cfg_base = info->cfg_base; int enabled; - /* User is shure about his config... accept it. */ + /* User is sure about his config... accept it. */ IRDA_DEBUG(2, "%s(): nsc_ircc_init_39x (user settings): " "io=0x%04x, irq=%d, dma=%d\n", __FUNCTION__, info->fir_base, info->irq, info->dma); diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 8429ceb0138..b82191d2bee 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -2283,7 +2283,7 @@ static void set_rx_mode(struct net_device *net_dev) int i, table_entries; u32 rx_mode; - /* 635 Hash Table entires = 256(2^16) */ + /* 635 Hash Table entries = 256(2^16) */ if((sis_priv->chipset_rev >= SIS635A_900_REV) || (sis_priv->chipset_rev == SIS900B_900_REV)) table_entries = 16; diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index ee48bfd6734..d1a86a080a6 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -513,7 +513,7 @@ struct mii_phy { u_char *rst; /* Start of reset sequence in SROM */ u_int mc; /* Media Capabilities */ u_int ana; /* NWay Advertisement */ - u_int fdx; /* Full DupleX capabilites for each media */ + u_int fdx; /* Full DupleX capabilities for each media */ u_int ttm; /* Transmit Threshold Mode for each media */ u_int mci; /* 21142 MII Connector Interrupt info */ }; diff --git a/drivers/net/tulip/pnic2.c b/drivers/net/tulip/pnic2.c index 55f4a9a631b..ab985023fcc 100644 --- a/drivers/net/tulip/pnic2.c +++ b/drivers/net/tulip/pnic2.c @@ -199,7 +199,7 @@ void pnic2_lnk_change(struct net_device *dev, int csr5) /* negotiation ended successfully */ /* get the link partners reply and mask out all but - * bits 24-21 which show the partners capabilites + * bits 24-21 which show the partners capabilities * and match those to what we advertised * * then begin to interpret the results of the negotiation. diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index cde35dd8790..c1ce87a5f8d 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -208,7 +208,7 @@ static const struct typhoon_card_info typhoon_card_info[] __devinitdata = { }; /* Notes on the new subsystem numbering scheme: - * bits 0-1 indicate crypto capabilites: (0) variable, (1) DES, or (2) 3DES + * bits 0-1 indicate crypto capabilities: (0) variable, (1) DES, or (2) 3DES * bit 4 indicates if this card has secured firmware (we don't support it) * bit 8 indicates if this is a (0) copper or (1) fiber card * bits 12-16 indicate card type: (0) client and (1) server @@ -788,7 +788,7 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev) /* we have two rings to choose from, but we only use txLo for now * If we start using the Hi ring as well, we'll need to update * typhoon_stop_runtime(), typhoon_interrupt(), typhoon_num_free_tx(), - * and TXHI_ENTIRES to match, as well as update the TSO code below + * and TXHI_ENTRIES to match, as well as update the TSO code below * to get the right DMA address */ txRing = &tp->txLoRing; diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 6fd0bf73683..8dfdfbd5966 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -3858,7 +3858,7 @@ static int orinoco_ioctl_setscan(struct net_device *dev, unsigned long flags; /* Note : you may have realised that, as this is a SET operation, - * this is priviledged and therefore a normal user can't + * this is privileged and therefore a normal user can't * perform scanning. * This is not an error, while the device perform scanning, * traffic doesn't flow, so it's a perfect DoS... diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index e5bb9f5ae42..989599ad33e 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -747,7 +747,7 @@ prism54_get_essid(struct net_device *ndev, struct iw_request_info *info, if (essid->length) { dwrq->flags = 1; /* set ESSID to ON for Wireless Extensions */ - /* if it is to big, trunk it */ + /* if it is too big, trunk it */ dwrq->length = min((u8)IW_ESSID_MAX_SIZE, essid->length); } else { dwrq->flags = 0; -- cgit v1.2.3 From 008652b337364ee994a0cd71d88a0fe9f00fc7ca Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 27 Mar 2006 23:14:53 -0800 Subject: [TG3]: Fix probe failure due to invalid MAC address Some older bootcode in some devices may report 0 MAC address in SRAM when booting up from low power state. This patch fixes the problem by checking for a valid MAC address in SRAM and falling back to NVRAM if necessary. Thanks to walt for reporting the problem and helping to debug it. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 50 ++++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b5473325bff..c41dbb0e8f1 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -10531,6 +10531,7 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) { struct net_device *dev = tp->dev; u32 hi, lo, mac_offset; + int addr_ok = 0; #ifdef CONFIG_SPARC64 if (!tg3_get_macaddr_sparc(tp)) @@ -10560,29 +10561,34 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) dev->dev_addr[3] = (lo >> 16) & 0xff; dev->dev_addr[4] = (lo >> 8) & 0xff; dev->dev_addr[5] = (lo >> 0) & 0xff; - } - /* Next, try NVRAM. */ - else if (!(tp->tg3_flags & TG3_FLG2_SUN_570X) && - !tg3_nvram_read(tp, mac_offset + 0, &hi) && - !tg3_nvram_read(tp, mac_offset + 4, &lo)) { - dev->dev_addr[0] = ((hi >> 16) & 0xff); - dev->dev_addr[1] = ((hi >> 24) & 0xff); - dev->dev_addr[2] = ((lo >> 0) & 0xff); - dev->dev_addr[3] = ((lo >> 8) & 0xff); - dev->dev_addr[4] = ((lo >> 16) & 0xff); - dev->dev_addr[5] = ((lo >> 24) & 0xff); - } - /* Finally just fetch it out of the MAC control regs. */ - else { - hi = tr32(MAC_ADDR_0_HIGH); - lo = tr32(MAC_ADDR_0_LOW); - dev->dev_addr[5] = lo & 0xff; - dev->dev_addr[4] = (lo >> 8) & 0xff; - dev->dev_addr[3] = (lo >> 16) & 0xff; - dev->dev_addr[2] = (lo >> 24) & 0xff; - dev->dev_addr[1] = hi & 0xff; - dev->dev_addr[0] = (hi >> 8) & 0xff; + /* Some old bootcode may report a 0 MAC address in SRAM */ + addr_ok = is_valid_ether_addr(&dev->dev_addr[0]); + } + if (!addr_ok) { + /* Next, try NVRAM. */ + if (!(tp->tg3_flags & TG3_FLG2_SUN_570X) && + !tg3_nvram_read(tp, mac_offset + 0, &hi) && + !tg3_nvram_read(tp, mac_offset + 4, &lo)) { + dev->dev_addr[0] = ((hi >> 16) & 0xff); + dev->dev_addr[1] = ((hi >> 24) & 0xff); + dev->dev_addr[2] = ((lo >> 0) & 0xff); + dev->dev_addr[3] = ((lo >> 8) & 0xff); + dev->dev_addr[4] = ((lo >> 16) & 0xff); + dev->dev_addr[5] = ((lo >> 24) & 0xff); + } + /* Finally just fetch it out of the MAC control regs. */ + else { + hi = tr32(MAC_ADDR_0_HIGH); + lo = tr32(MAC_ADDR_0_LOW); + + dev->dev_addr[5] = lo & 0xff; + dev->dev_addr[4] = (lo >> 8) & 0xff; + dev->dev_addr[3] = (lo >> 16) & 0xff; + dev->dev_addr[2] = (lo >> 24) & 0xff; + dev->dev_addr[1] = hi & 0xff; + dev->dev_addr[0] = (hi >> 8) & 0xff; + } } if (!is_valid_ether_addr(&dev->dev_addr[0])) { -- cgit v1.2.3 From 6728a8e2e180b96ac7940dd4d766c52f8e177717 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 27 Mar 2006 23:16:49 -0800 Subject: [TG3]: Fix bug in 40-bit DMA workaround code Need to check the TG3_FLAG_40BIT_DMA_BUG flag in the workaround code path instead of device flags. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index c41dbb0e8f1..0fafc526462 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -3600,7 +3600,7 @@ static inline int tg3_40bit_overflow_test(struct tg3 *tp, dma_addr_t mapping, int len) { #if defined(CONFIG_HIGHMEM) && (BITS_PER_LONG == 64) - if (tp->tg3_flags2 & TG3_FLG2_5780_CLASS) + if (tp->tg3_flags & TG3_FLAG_40BIT_DMA_BUG) return (((u64) mapping + len) > DMA_40BIT_MASK); return 0; #else -- cgit v1.2.3 From ff18ff023495a4f1ce7c65e7c376c4720eccf4da Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 27 Mar 2006 23:17:27 -0800 Subject: [TG3]: Fix PHY loopback on 5700 Fix PHY loopback failure on some 5700 devices. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 0fafc526462..3c5c9fafe9c 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -8399,8 +8399,11 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode) } mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) | MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII; - if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) + if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) { mac_mode &= ~MAC_MODE_LINK_POLARITY; + tg3_writephy(tp, MII_TG3_EXT_CTRL, + MII_TG3_EXT_CTRL_LNK3_LED_MODE); + } tw32(MAC_MODE, mac_mode); } else -- cgit v1.2.3 From 100c4673307f5806788791b9b886877c806afd96 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 27 Mar 2006 23:19:00 -0800 Subject: [TG3]: Speed up SRAM access Speed up SRAM read and write functions if possible by using MMIO instead of config. cycles. With this change, the post reset signature done at the end of D3 power change must now be moved before the D3 power change. IBM reported a problem on powerpc blades during ethtool self test that was caused by the memory test taking excessively long. Config. cycles are very slow on powerpc and the memory test can take more than 10 seconds to complete using config. cycles. As a result, NETDEV WATCHDOG can be triggered during self test and the chip can end up in a funny state. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 53 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 23 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index 3c5c9fafe9c..c504ff29d44 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -497,21 +497,20 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val) unsigned long flags; spin_lock_irqsave(&tp->indirect_lock, flags); - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); + if (tp->write32 != tg3_write_indirect_reg32) { + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off); + tw32_f(TG3PCI_MEM_WIN_DATA, val); - /* Always leave this as zero. */ - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); - spin_unlock_irqrestore(&tp->indirect_lock, flags); -} + /* Always leave this as zero. */ + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0); + } else { + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); -static void tg3_write_mem_fast(struct tg3 *tp, u32 off, u32 val) -{ - /* If no workaround is needed, write to mem space directly */ - if (tp->write32 != tg3_write_indirect_reg32) - tw32(NIC_SRAM_WIN_BASE + off, val); - else - tg3_write_mem(tp, off, val); + /* Always leave this as zero. */ + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + } + spin_unlock_irqrestore(&tp->indirect_lock, flags); } static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) @@ -519,11 +518,19 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val) unsigned long flags; spin_lock_irqsave(&tp->indirect_lock, flags); - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); - pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); + if (tp->write32 != tg3_write_indirect_reg32) { + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, off); + *val = tr32(TG3PCI_MEM_WIN_DATA); - /* Always leave this as zero. */ - pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + /* Always leave this as zero. */ + tw32_f(TG3PCI_MEM_WIN_BASE_ADDR, 0); + } else { + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off); + pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val); + + /* Always leave this as zero. */ + pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0); + } spin_unlock_irqrestore(&tp->indirect_lock, flags); } @@ -1367,12 +1374,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) } } + tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); + /* Finally, set the new power state. */ pci_write_config_word(tp->pdev, pm + PCI_PM_CTRL, power_control); udelay(100); /* Delay after power state change */ - tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); - return 0; } @@ -6537,11 +6544,11 @@ static void tg3_timer(unsigned long __opaque) if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { u32 val; - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_MBOX, - FWCMD_NICDRV_ALIVE2); - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, + FWCMD_NICDRV_ALIVE2); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); /* 5 seconds timeout */ - tg3_write_mem_fast(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5); val = tr32(GRC_RX_CPU_EVENT); val |= (1 << 14); tw32(GRC_RX_CPU_EVENT, val); -- cgit v1.2.3 From f475f163f128a0d9c92dfa90bcb5953fd8f9766f Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 27 Mar 2006 23:20:14 -0800 Subject: [TG3]: Skip timer code during full lock Skip the main timer code if interrupts are disabled in the full lock state. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index c504ff29d44..b6a6051db77 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -6468,6 +6468,9 @@ static void tg3_timer(unsigned long __opaque) { struct tg3 *tp = (struct tg3 *) __opaque; + if (tp->irq_sync) + goto restart_timer; + spin_lock(&tp->lock); if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) { @@ -6558,6 +6561,7 @@ static void tg3_timer(unsigned long __opaque) spin_unlock(&tp->lock); +restart_timer: tp->timer.expires = jiffies + tp->timer_offset; add_timer(&tp->timer); } -- cgit v1.2.3 From e3a05978f18a38ae13bb3f1184abf3c999e06da9 Mon Sep 17 00:00:00 2001 From: Michael Chan Date: Mon, 27 Mar 2006 23:21:07 -0800 Subject: [TG3]: Update version and reldate Update version to 3.55. Signed-off-by: Michael Chan Signed-off-by: David S. Miller --- drivers/net/tg3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index b6a6051db77..964c0964483 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -69,8 +69,8 @@ #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.54" -#define DRV_MODULE_RELDATE "Mar 23, 2006" +#define DRV_MODULE_VERSION "3.55" +#define DRV_MODULE_RELDATE "Mar 27, 2006" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 -- cgit v1.2.3 From 5c5131297db57b501f371ab53c40343eac6f2af7 Mon Sep 17 00:00:00 2001 From: Gary Zambrano Date: Wed, 29 Mar 2006 17:12:05 -0500 Subject: b44: fix force mac address before ifconfig up Initializing the b44 MAC & PCI functional blocks in the controller must occur inside init_one(). This will allow access to the MAC registers. The controller was being powered up in b44_open() which would not allow access to the registers before ifconfig was up. Philip Kohlbecher found this bug. Signed-off-by: Gary Zambrano --- drivers/net/b44.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index c3267e4e1bb..2eab2a88c7b 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -2033,6 +2033,11 @@ static int __devinit b44_init_one(struct pci_dev *pdev, pci_save_state(bp->pdev); + /* Chip reset provides power to the b44 MAC & PCI cores, which + * is necessary for MAC register access. + */ + b44_chip_reset(bp); + printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name); for (i = 0; i < 6; i++) printk("%2.2x%c", dev->dev_addr[i], -- cgit v1.2.3 From b8ab2dc3e1a7c525ca73ba0af3518ec0b7654b3b Mon Sep 17 00:00:00 2001 From: Komuro Date: Sun, 26 Mar 2006 07:31:55 +0900 Subject: [PATCH] axnet_cs.c : add hardware multicast support Signed-off-by: Jeff Garzik --- drivers/net/pcmcia/axnet_cs.c | 61 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 8 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index aa558136939..1cc94b2d76c 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "../8390.h" #include @@ -1682,17 +1683,67 @@ static struct net_device_stats *get_stats(struct net_device *dev) return &ei_local->stat; } +/* + * Form the 64 bit 8390 multicast table from the linked list of addresses + * associated with this dev structure. + */ + +static inline void make_mc_bits(u8 *bits, struct net_device *dev) +{ + struct dev_mc_list *dmi; + u32 crc; + + for (dmi=dev->mc_list; dmi; dmi=dmi->next) { + + crc = ether_crc(ETH_ALEN, dmi->dmi_addr); + /* + * The 8390 uses the 6 most significant bits of the + * CRC to index the multicast table. + */ + bits[crc>>29] |= (1<<((crc>>26)&7)); + } +} + /** * do_set_multicast_list - set/clear multicast filter * @dev: net device for which multicast filter is adjusted * - * Set or clear the multicast filter for this adaptor. May be called - * from a BH in 2.1.x. Must be called with lock held. + * Set or clear the multicast filter for this adaptor. + * Must be called with lock held. */ static void do_set_multicast_list(struct net_device *dev) { long e8390_base = dev->base_addr; + int i; + struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev); + + if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) { + memset(ei_local->mcfilter, 0, 8); + if (dev->mc_list) + make_mc_bits(ei_local->mcfilter, dev); + } else { + /* set to accept-all */ + memset(ei_local->mcfilter, 0xFF, 8); + } + + /* + * DP8390 manuals don't specify any magic sequence for altering + * the multicast regs on an already running card. To be safe, we + * ensure multicast mode is off prior to loading up the new hash + * table. If this proves to be not enough, we can always resort + * to stopping the NIC, loading the table and then restarting. + */ + + if (netif_running(dev)) + outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); + + outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD); + for(i = 0; i < 8; i++) + { + outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i)); + } + outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD); if(dev->flags&IFF_PROMISC) outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR); @@ -1794,12 +1845,6 @@ static void AX88190_init(struct net_device *dev, int startp) if(inb_p(e8390_base + EN1_PHYS_SHIFT(i))!=dev->dev_addr[i]) printk(KERN_ERR "Hw. address read/write mismap %d\n",i); } - /* - * Initialize the multicast list to accept-all. If we enable multicast - * the higher levels can do the filtering. - */ - for (i = 0; i < 8; i++) - outb_p(0xff, e8390_base + EN1_MULT + i); outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG); outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD); -- cgit v1.2.3 From 00b428c2ab35c81905b3e39d673689216dbd4742 Mon Sep 17 00:00:00 2001 From: Roger Luethi Date: Tue, 28 Mar 2006 20:53:56 +0200 Subject: [PATCH] via-rhine: link state fix Problems with link state detection have been reported several times in the past months. Denis Vlasenko did all the work tracking it down. Jeff Garzik suggested the proper place for the fix. When using the mii library, the driver needs to check mii->force_media and set dev->state accordingly. Signed-off-by: Roger Luethi Signed-off-by: Jeff Garzik --- drivers/net/via-rhine.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 24187158928..a9b2150909d 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -1085,6 +1085,25 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media) else iowrite8(ioread8(ioaddr + ChipCmd1) & ~Cmd1FDuplex, ioaddr + ChipCmd1); + if (debug > 1) + printk(KERN_INFO "%s: force_media %d, carrier %d\n", dev->name, + rp->mii_if.force_media, netif_carrier_ok(dev)); +} + +/* Called after status of force_media possibly changed */ +void rhine_set_carrier(struct mii_if_info *mii) +{ + if (mii->force_media) { + /* autoneg is off: Link is always assumed to be up */ + if (!netif_carrier_ok(mii->dev)) + netif_carrier_on(mii->dev); + } + else /* Let MMI library update carrier status */ + rhine_check_media(mii->dev, 0); + if (debug > 1) + printk(KERN_INFO "%s: force_media %d, carrier %d\n", + mii->dev->name, mii->force_media, + netif_carrier_ok(mii->dev)); } static void rhine_check_media_task(struct net_device *dev) @@ -1782,6 +1801,7 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) spin_lock_irq(&rp->lock); rc = mii_ethtool_sset(&rp->mii_if, cmd); spin_unlock_irq(&rp->lock); + rhine_set_carrier(&rp->mii_if); return rc; } @@ -1869,6 +1889,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) spin_lock_irq(&rp->lock); rc = generic_mii_ioctl(&rp->mii_if, if_mii(rq), cmd, NULL); spin_unlock_irq(&rp->lock); + rhine_set_carrier(&rp->mii_if); return rc; } -- cgit v1.2.3 From 4e5077b62b1f67fe0df916e387da4a6dabe577e9 Mon Sep 17 00:00:00 2001 From: Jens Osterkamp Date: Tue, 28 Mar 2006 15:59:55 +0200 Subject: [PATCH] spidernet : reduce console spam This patch reduces the message level of the RX ram full messages from err to debug to prevent spamming the console leaving it in the logfiles though. From: Jens Osterkamp Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 1f5975a61e1..0000de01ec1 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -1442,7 +1442,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) case SPIDER_NET_GRFAFLLINT: /* fallthrough */ case SPIDER_NET_GRMFLLINT: if (netif_msg_intr(card) && net_ratelimit()) - pr_err("Spider RX RAM full, incoming packets " + pr_debug("Spider RX RAM full, incoming packets " "might be discarded!\n"); spider_net_rx_irq_off(card); tasklet_schedule(&card->rxram_full_tl); -- cgit v1.2.3 From 8a89334caf80bb7c86383b73fd5a528cb88c696f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 27 Mar 2006 12:26:12 -0800 Subject: [PATCH] acenic: fix section mismatches Fix section mismatches in acenic driver: WARNING: drivers/net/acenic.o - Section mismatch: reference to .init.data:tigon2FwText from .text between 'acenic_probe_one' (at offset 0x2409) and 'ace_interrupt' WARNING: drivers/net/acenic.o - Section mismatch: reference to .init.data:tigon2FwRodata from .text between 'acenic_probe_one' (at offset 0x2422) and 'ace_interrupt' Signed-off-by: Randy Dunlap Signed-off-by: Jeff Garzik --- drivers/net/acenic_firmware.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/acenic_firmware.h b/drivers/net/acenic_firmware.h index 6d625d59562..d7882dd783c 100644 --- a/drivers/net/acenic_firmware.h +++ b/drivers/net/acenic_firmware.h @@ -4397,7 +4397,7 @@ static u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = { 0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 }; -static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { +static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66, 0x772f636f, 0x6d6d6f6e, @@ -4571,7 +4571,7 @@ static u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x0, 0x14c38, 0x14c38, 0x14b80, 0x14bc4, 0x14c38, 0x14c38, 0x0, 0x0, 0x0 }; -static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = { +static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __devinitdata = { 0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465, 0x6f6e2041, 0x63654e49, 0x43205600, 0x42424242, @@ -4612,7 +4612,7 @@ static u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = { #define tigon2FwSbssLen 0xcc #define tigon2FwBssAddr 0x00016f50 #define tigon2FwBssLen 0x20c0 -static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { +static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __devinitdata = { 0x0, 0x10000003, 0x0, 0xd, 0xd, 0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000, @@ -9154,7 +9154,7 @@ static u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = { 0x24020001, 0x8f430328, 0x1021, 0x24630001, 0x3e00008, 0xaf430328, 0x3e00008, 0x0, 0x0, 0x0, 0x0, 0x0 }; -static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { +static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __devinitdata = { 0x24486561, 0x6465723a, 0x202f7072, 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, @@ -9425,7 +9425,7 @@ static u32 tigon2FwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = { 0x14ed8, 0x14b8c, 0x14bd8, 0x14c24, 0x14ed8, 0x7365746d, 0x61636163, 0x74000000, 0x0, 0x0 }; -static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = { +static u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __devinitdata = { 0x1, 0x1, 0x1, 0xc001fc, 0x3ffc, 0xc00000, 0x416c7465, 0x6f6e2041, 0x63654e49, -- cgit v1.2.3 From ff59c4563a8d1b39597aab4917959146c61f09b0 Mon Sep 17 00:00:00 2001 From: Jay Vosburgh Date: Mon, 27 Mar 2006 13:27:43 -0800 Subject: [PATCH] bonding: support carrier state for master Add support for the bonding master to specify its carrier state based upon the state of the slaves. For 802.3ad, the bond is up if there is an active, parterned aggregator. For other modes, the bond is up if any slaves are up. Updates driver version to 3.0.3. Based on a patch by jamal . Signed-off-by: Jay Vosburgh Signed-off-by: Jeff Garzik --- drivers/net/bonding/bond_3ad.c | 28 ++++++++++++ drivers/net/bonding/bond_3ad.h | 1 + drivers/net/bonding/bond_main.c | 97 ++++++++++++++++++++++++++++++----------- drivers/net/bonding/bonding.h | 4 +- 4 files changed, 102 insertions(+), 28 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index f3f5825469d..6a407070c2e 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -2294,6 +2294,34 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) port->sm_vars |= AD_PORT_BEGIN; } +/* + * set link state for bonding master: if we have an active partnered + * aggregator, we're up, if not, we're down. Presumes that we cannot + * have an active aggregator if there are no slaves with link up. + * + * Called by bond_set_carrier(). Return zero if carrier state does not + * change, nonzero if it does. + */ +int bond_3ad_set_carrier(struct bonding *bond) +{ + struct aggregator *agg; + + agg = __get_active_agg(&(SLAVE_AD_INFO(bond->first_slave).aggregator)); + if (agg && MAC_ADDRESS_COMPARE(&agg->partner_system, &null_mac_addr)) { + if (!netif_carrier_ok(bond->dev)) { + netif_carrier_on(bond->dev); + return 1; + } + return 0; + } + + if (netif_carrier_ok(bond->dev)) { + netif_carrier_off(bond->dev); + return 1; + } + return 0; +} + /** * bond_3ad_get_active_agg_info - get information of the active aggregator * @bond: bonding struct to work on diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index 5ee2cef5b03..6ad5ad6e65d 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -283,5 +283,6 @@ void bond_3ad_handle_link_change(struct slave *slave, char link); int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info); int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev); int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev); +int bond_3ad_set_carrier(struct bonding *bond); #endif //__BOND_3AD_H__ diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index f13a539dc16..55d236726d1 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -558,6 +558,42 @@ out: /*------------------------------- Link status -------------------------------*/ +/* + * Set the carrier state for the master according to the state of its + * slaves. If any slaves are up, the master is up. In 802.3ad mode, + * do special 802.3ad magic. + * + * Returns zero if carrier state does not change, nonzero if it does. + */ +static int bond_set_carrier(struct bonding *bond) +{ + struct slave *slave; + int i; + + if (bond->slave_cnt == 0) + goto down; + + if (bond->params.mode == BOND_MODE_8023AD) + return bond_3ad_set_carrier(bond); + + bond_for_each_slave(bond, slave, i) { + if (slave->link == BOND_LINK_UP) { + if (!netif_carrier_ok(bond->dev)) { + netif_carrier_on(bond->dev); + return 1; + } + return 0; + } + } + +down: + if (netif_carrier_ok(bond->dev)) { + netif_carrier_off(bond->dev); + return 1; + } + return 0; +} + /* * Get link speed and duplex from the slave's base driver * using ethtool. If for some reason the call fails or the @@ -1074,10 +1110,24 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) void bond_select_active_slave(struct bonding *bond) { struct slave *best_slave; + int rv; best_slave = bond_find_best_slave(bond); if (best_slave != bond->curr_active_slave) { bond_change_active_slave(bond, best_slave); + rv = bond_set_carrier(bond); + if (!rv) + return; + + if (netif_carrier_ok(bond->dev)) { + printk(KERN_INFO DRV_NAME + ": %s: first active interface up!\n", + bond->dev->name); + } else { + printk(KERN_INFO DRV_NAME ": %s: " + "now running without any active interface !\n", + bond->dev->name); + } } } @@ -1458,10 +1508,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (((!bond->curr_active_slave) || (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) && (new_slave->link != BOND_LINK_DOWN)) { - dprintk("This is the first active slave\n"); /* first slave or no active slave yet, and this link is OK, so make this interface the active one */ bond_change_active_slave(bond, new_slave); + printk(KERN_INFO DRV_NAME + ": %s: first active interface up!\n", + bond->dev->name); + netif_carrier_on(bond->dev); + } else { dprintk("This is just a backup slave\n"); bond_set_slave_inactive_flags(new_slave); @@ -1517,6 +1571,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) break; } /* switch(bond_mode) */ + bond_set_carrier(bond); + write_unlock_bh(&bond->lock); res = bond_create_slave_symlinks(bond_dev, slave_dev); @@ -1656,18 +1712,12 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) bond_alb_deinit_slave(bond, slave); } - if (oldcurrent == slave) { + if (oldcurrent == slave) bond_select_active_slave(bond); - if (!bond->curr_active_slave) { - printk(KERN_INFO DRV_NAME - ": %s: now running without any active " - "interface !\n", - bond_dev->name); - } - } - if (bond->slave_cnt == 0) { + bond_set_carrier(bond); + /* if the last slave was removed, zero the mac address * of the master so it will be set by the application * to the mac address of the first slave @@ -1751,6 +1801,8 @@ static int bond_release_all(struct net_device *bond_dev) write_lock_bh(&bond->lock); + netif_carrier_off(bond_dev); + if (bond->slave_cnt == 0) { goto out; } @@ -2187,15 +2239,9 @@ void bond_mii_monitor(struct net_device *bond_dev) bond_select_active_slave(bond); - if (oldcurrent && !bond->curr_active_slave) { - printk(KERN_INFO DRV_NAME - ": %s: now running without any active " - "interface !\n", - bond_dev->name); - } - write_unlock(&bond->curr_slave_lock); - } + } else + bond_set_carrier(bond); re_arm: if (bond->params.miimon) { @@ -2499,13 +2545,6 @@ void bond_loadbalance_arp_mon(struct net_device *bond_dev) bond_select_active_slave(bond); - if (oldcurrent && !bond->curr_active_slave) { - printk(KERN_INFO DRV_NAME - ": %s: now running without any active " - "interface !\n", - bond_dev->name); - } - write_unlock(&bond->curr_slave_lock); } @@ -2579,12 +2618,15 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev) bond->current_arp_slave = NULL; } + bond_set_carrier(bond); + if (slave == bond->curr_active_slave) { printk(KERN_INFO DRV_NAME ": %s: %s is up and now the " "active interface\n", bond_dev->name, slave->dev->name); + netif_carrier_on(bond->dev); } else { printk(KERN_INFO DRV_NAME ": %s: backup interface %s is " @@ -2844,7 +2886,8 @@ static void bond_info_show_master(struct seq_file *seq) (curr) ? curr->dev->name : "None"); } - seq_printf(seq, "MII Status: %s\n", (curr) ? "up" : "down"); + seq_printf(seq, "MII Status: %s\n", netif_carrier_ok(bond->dev) ? + "up" : "down"); seq_printf(seq, "MII Polling Interval (ms): %d\n", bond->params.miimon); seq_printf(seq, "Up Delay (ms): %d\n", bond->params.updelay * bond->params.miimon); @@ -4531,6 +4574,8 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond if (newbond) *newbond = bond_dev->priv; + netif_carrier_off(bond_dev); + rtnl_unlock(); /* allows sysfs registration of net device */ res = bond_create_sysfs_entry(bond_dev->priv); goto done; diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index ce9dc9b4e2d..0bdfe2c7145 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -22,8 +22,8 @@ #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.0.2" -#define DRV_RELDATE "February 21, 2006" +#define DRV_VERSION "3.0.3" +#define DRV_RELDATE "March 23, 2006" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" -- cgit v1.2.3 From 8dfc914a3f2ae4e303e2bff89f28fc14cee8a9a6 Mon Sep 17 00:00:00 2001 From: Jens Osterkamp Date: Mon, 27 Mar 2006 17:16:36 +0200 Subject: [PATCH] spidernet : enable tx checksum offloading by default This enables TX checksum offloading for the spidernet driver by default. Signed-off-by: Jens Osterkamp Signed-off-by: Jeff Garzik --- drivers/net/spider_net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 0000de01ec1..43f5e86fc55 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -2086,7 +2086,7 @@ spider_net_setup_netdev(struct spider_net_card *card) spider_net_setup_netdev_ops(netdev); - netdev->features = 0; + netdev->features = NETIF_F_HW_CSUM; /* some time: NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | * NETIF_F_HW_VLAN_FILTER */ -- cgit v1.2.3 From a8b4cf42cf57e44e3c4a585e0f0a71e3a7efbf29 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Tue, 28 Mar 2006 14:08:55 -0800 Subject: [PATCH] natsemi: Support oversized EEPROMs The natsemi chip can have a larger EEPROM attached than it itself uses for configuration. This patch adds support for user space access to such an EEPROM. Signed-off-by: Mark Brown Cc: Tim Hockin Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/natsemi.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index 8d4999837b6..7826afbb9db 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -226,7 +226,7 @@ static int full_duplex[MAX_UNITS]; NATSEMI_PG1_NREGS) #define NATSEMI_REGS_VER 1 /* v1 added RFDR registers */ #define NATSEMI_REGS_SIZE (NATSEMI_NREGS * sizeof(u32)) -#define NATSEMI_EEPROM_SIZE 24 /* 12 16-bit values */ +#define NATSEMI_DEF_EEPROM_SIZE 24 /* 12 16-bit values */ /* Buffer sizes: * The nic writes 32-bit values, even if the upper bytes of @@ -714,6 +714,8 @@ struct netdev_private { unsigned int iosize; spinlock_t lock; u32 msg_enable; + /* EEPROM data */ + int eeprom_size; }; static void move_int_phy(struct net_device *dev, int addr); @@ -890,6 +892,7 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, np->msg_enable = (debug >= 0) ? (1<hands_off = 0; np->intr_status = 0; + np->eeprom_size = NATSEMI_DEF_EEPROM_SIZE; /* Initial port: * - If the nic was configured to use an external phy and if find_mii @@ -2582,7 +2585,8 @@ static int get_regs_len(struct net_device *dev) static int get_eeprom_len(struct net_device *dev) { - return NATSEMI_EEPROM_SIZE; + struct netdev_private *np = netdev_priv(dev); + return np->eeprom_size; } static int get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) @@ -2669,15 +2673,20 @@ static u32 get_link(struct net_device *dev) static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { struct netdev_private *np = netdev_priv(dev); - u8 eebuf[NATSEMI_EEPROM_SIZE]; + u8 *eebuf; int res; + eebuf = kmalloc(np->eeprom_size, GFP_KERNEL); + if (!eebuf) + return -ENOMEM; + eeprom->magic = PCI_VENDOR_ID_NS | (PCI_DEVICE_ID_NS_83815<<16); spin_lock_irq(&np->lock); res = netdev_get_eeprom(dev, eebuf); spin_unlock_irq(&np->lock); if (!res) memcpy(data, eebuf+eeprom->offset, eeprom->len); + kfree(eebuf); return res; } @@ -3033,9 +3042,10 @@ static int netdev_get_eeprom(struct net_device *dev, u8 *buf) int i; u16 *ebuf = (u16 *)buf; void __iomem * ioaddr = ns_ioaddr(dev); + struct netdev_private *np = netdev_priv(dev); /* eeprom_read reads 16 bits, and indexes by 16 bits */ - for (i = 0; i < NATSEMI_EEPROM_SIZE/2; i++) { + for (i = 0; i < np->eeprom_size/2; i++) { ebuf[i] = eeprom_read(ioaddr, i); /* The EEPROM itself stores data bit-swapped, but eeprom_read * reads it back "sanely". So we swap it back here in order to -- cgit v1.2.3 From 8a91ed60f58451342a25f3ab4484c7257430aa8e Mon Sep 17 00:00:00 2001 From: Arthur Othieno Date: Tue, 28 Mar 2006 14:09:01 -0800 Subject: [PATCH] net: remove CONFIG_NET_CBUS conditional for NS8390 Don't bother testing for CONFIG_NET_CBUS ("NEC PC-9800 C-bus cards"); it went out with the rest of PC98 subarch. Signed-off-by: Arthur Othieno Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik --- drivers/net/8390.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/net') diff --git a/drivers/net/8390.h b/drivers/net/8390.h index 599b68d8c45..51e39dcd060 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -134,7 +134,7 @@ struct ei_device { #define inb_p(_p) inb(_p) #define outb_p(_v,_p) outb(_v,_p) -#elif defined(CONFIG_NET_CBUS) || defined(CONFIG_NE_H8300) || defined(CONFIG_NE_H8300_MODULE) +#elif defined(CONFIG_NE_H8300) || defined(CONFIG_NE_H8300_MODULE) #define EI_SHIFT(x) (ei_local->reg_offset[x]) #else #define EI_SHIFT(x) (x) -- cgit v1.2.3 From bc0e1fc970279c539db1e94dd473acbb193ee473 Mon Sep 17 00:00:00 2001 From: Linas Vepstas Date: Tue, 28 Mar 2006 16:36:23 -0600 Subject: [PATCH] Janitor: drivers/net/pcnet32: fix incorrect comments The comments concerning how the pcnet32 ethernet device driver selects the MAC addr to use are incorrect. A recent patch (in the last 3 months) changed how the code worked, but did not change the comments. Side comment: the new behaviour is good; I've got a pcnet32 card which powers up with garbage in the CSR's, and a good MAC addr in the PROM. Signed-off-by: Linas Vepstas Signed-off-by: Jeff Garzik --- drivers/net/pcnet32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 9595f74da93..07c31f19c6b 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1167,8 +1167,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) * station address PROM at the base address and programmed into the * "Physical Address Registers" CSR12-14. * As a precautionary measure, we read the PROM values and complain if - * they disagree with the CSRs. Either way, we use the CSR values, and - * double check that they are valid. + * they disagree with the CSRs. If they miscompare, and the PROM addr + * is valid, then the PROM addr is used. */ for (i = 0; i < 3; i++) { unsigned int val; -- cgit v1.2.3 From 391fc09a143aac08d1a3dc37b60238612b504ad3 Mon Sep 17 00:00:00 2001 From: Gary Zambrano Date: Tue, 28 Mar 2006 14:57:38 -0800 Subject: [PATCH] b44: ensure valid mac addr Added code to check for invalid MAC address from eeprom or user input. Signed-off-by: Gary Zambrano Signed-off-by: Jeff Garzik --- drivers/net/b44.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/net') diff --git a/drivers/net/b44.c b/drivers/net/b44.c index 2eab2a88c7b..15032f2c781 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -1339,6 +1339,9 @@ static int b44_set_mac_addr(struct net_device *dev, void *p) if (netif_running(dev)) return -EBUSY; + if (!is_valid_ether_addr(addr->sa_data)) + return -EINVAL; + memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); spin_lock_irq(&bp->lock); @@ -1876,6 +1879,12 @@ static int __devinit b44_get_invariants(struct b44 *bp) bp->dev->dev_addr[3] = eeprom[80]; bp->dev->dev_addr[4] = eeprom[83]; bp->dev->dev_addr[5] = eeprom[82]; + + if (!is_valid_ether_addr(&bp->dev->dev_addr[0])){ + printk(KERN_ERR PFX "Invalid MAC address found in EEPROM\n"); + return -EINVAL; + } + memcpy(bp->dev->perm_addr, bp->dev->dev_addr, bp->dev->addr_len); bp->phy_addr = eeprom[90] & 0x1f; -- cgit v1.2.3 From 5d4fe2c1ce83c3e967ccc1ba3d580c1a5603a866 Mon Sep 17 00:00:00 2001 From: Lennert Buytenhek Date: Wed, 29 Mar 2006 15:12:44 +0200 Subject: [PATCH] ixp2000: fix gcc4 breakage gcc4 doesn't like us declaring a static function inside another function. We can do away with this construct altogether and use BUILD_BUG_ON() instead (idea from Andi Kleen.) Signed-off-by: Lennert Buytenhek Signed-off-by: Jeff Garzik --- drivers/net/ixp2000/ixpdev.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 77f104a005f..fbc2d21020f 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -299,10 +299,7 @@ int ixpdev_init(int __nds_count, struct net_device **__nds, int i; int err; - if (RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192) { - static void __too_many_rx_or_tx_buffers(void); - __too_many_rx_or_tx_buffers(); - } + BUILD_BUG_ON(RX_BUF_COUNT > 192 || TX_BUF_COUNT > 192); printk(KERN_INFO "IXP2000 MSF ethernet driver %s\n", DRV_MODULE_VERSION); -- cgit v1.2.3 From 694a464e19b9e3278dbaf6a09fa7c1efec3f8eb5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 31 Mar 2006 02:30:14 -0800 Subject: [PATCH] uml: kconfigs kconfig sanitized around drivers/net Signed-off-by: Al Viro Signed-off-by: Jeff Dike Cc: Paolo 'Blaisorblade' Giarrusso Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/Kconfig | 2 -- drivers/net/tokenring/Kconfig | 2 +- drivers/net/wireless/Kconfig | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index e20b849a22e..bdaaad8f212 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -2313,13 +2313,11 @@ config S2IO_NAPI endmenu -if !UML source "drivers/net/tokenring/Kconfig" source "drivers/net/wireless/Kconfig" source "drivers/net/pcmcia/Kconfig" -endif source "drivers/net/wan/Kconfig" diff --git a/drivers/net/tokenring/Kconfig b/drivers/net/tokenring/Kconfig index e4cfc80b283..99c4c1922f1 100644 --- a/drivers/net/tokenring/Kconfig +++ b/drivers/net/tokenring/Kconfig @@ -3,7 +3,7 @@ # menu "Token Ring devices" - depends on NETDEVICES + depends on NETDEVICES && !UML # So far, we only have PCI, ISA, and MCA token ring devices config TR diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index f85e3019000..bad09ebdb50 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -356,7 +356,7 @@ config PCI_HERMES config ATMEL tristate "Atmel at76c50x chipset 802.11b support" - depends on NET_RADIO + depends on NET_RADIO && (PCI || PCMCIA) select FW_LOADER select CRC32 ---help--- -- cgit v1.2.3 From 9b41046cd0ee0a57f849d6e1363f7933e363cca9 Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Fri, 31 Mar 2006 02:30:33 -0800 Subject: [PATCH] Don't pass boot parameters to argv_init[] The boot cmdline is parsed in parse_early_param() and parse_args(,unknown_bootoption). And __setup() is used in obsolete_checksetup(). start_kernel() -> parse_args() -> unknown_bootoption() -> obsolete_checksetup() If __setup()'s callback (->setup_func()) returns 1 in obsolete_checksetup(), obsolete_checksetup() thinks a parameter was handled. If ->setup_func() returns 0, obsolete_checksetup() tries other ->setup_func(). If all ->setup_func() that matched a parameter returns 0, a parameter is seted to argv_init[]. Then, when runing /sbin/init or init=app, argv_init[] is passed to the app. If the app doesn't ignore those arguments, it will warning and exit. This patch fixes a wrong usage of it, however fixes obvious one only. Signed-off-by: OGAWA Hirofumi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/netconsole.c | 2 +- drivers/net/pcmcia/xirc2ps_cs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index edd1b5306b1..75b35ad760d 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -94,7 +94,7 @@ static struct console netconsole = { static int option_setup(char *opt) { configured = !netpoll_parse_options(&np, opt); - return 0; + return 1; } __setup("netconsole=", option_setup); diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index eed496803fe..e8f849e1297 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -1973,7 +1973,7 @@ static int __init setup_xirc2ps_cs(char *str) MAYBE_SET(lockup_hack, 6); #undef MAYBE_SET - return 0; + return 1; } __setup("xirc2ps_cs=", setup_xirc2ps_cs); -- cgit v1.2.3 From 0000754c27f07d5656eff17367c05dc4cfb7d965 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 31 Mar 2006 02:30:47 -0800 Subject: [PATCH] "3c59x collision statistics fix" fix The pre-2.6.16 patch "3c59x collision statistics fix" accidentally caused vortex_error() to not run iowrite16(TxEnable, ioaddr + EL3_CMD) if we got a maxCollisions interrupt but MAX_COLLISION_RESET is not set. Thanks to Pete Clements for reporting and testing. Acked-by: Steffen Klassert Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/3c59x.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 70f63891b19..51129079853 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -2083,16 +2083,14 @@ vortex_error(struct net_device *dev, int status) } if (tx_status & 0x14) vp->stats.tx_fifo_errors++; if (tx_status & 0x38) vp->stats.tx_aborted_errors++; + if (tx_status & 0x08) vp->xstats.tx_max_collisions++; iowrite8(0, ioaddr + TxStatus); if (tx_status & 0x30) { /* txJabber or txUnderrun */ do_tx_reset = 1; - } else if (tx_status & 0x08) { /* maxCollisions */ - vp->xstats.tx_max_collisions++; - if (vp->drv_flags & MAX_COLLISION_RESET) { - do_tx_reset = 1; - reset_mask = 0x0108; /* Reset interface logic, but not download logic */ - } - } else { /* Merely re-enable the transmitter. */ + } else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET)) { /* maxCollisions */ + do_tx_reset = 1; + reset_mask = 0x0108; /* Reset interface logic, but not download logic */ + } else { /* Merely re-enable the transmitter. */ iowrite16(TxEnable, ioaddr + EL3_CMD); } } -- cgit v1.2.3 From 09ce3512dcad0ad1d07eee0dc5ebb6d037c39c16 Mon Sep 17 00:00:00 2001 From: Steffen Klassert Date: Fri, 31 Mar 2006 02:30:48 -0800 Subject: [PATCH] 3c59x: fix networking for 10base2 NICs The "3c59x: use mii_check_media" patch introduced a netif_carrier_off in vortex_up. 10base2 stoped working because of this. This is removed. Tx/Rx reset is back in vortex_up because the 3c900B-Combo stops working after changing from half duplex to full duplex when Tx/Rx reset is done with vortex_timer. Also brought back some mii stuff to be sure that it does not break something else. Thanks to Pete Clements for reporting and testing. Signed-off-by: Steffen Klassert Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/3c59x.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers/net') diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 51129079853..274b0138d44 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -788,7 +788,7 @@ struct vortex_private { int options; /* User-settable misc. driver options. */ unsigned int media_override:4, /* Passed-in media type. */ default_media:4, /* Read from the EEPROM/Wn3_Config. */ - full_duplex:1, force_fd:1, autoselect:1, + full_duplex:1, autoselect:1, bus_master:1, /* Vortex can only do a fragment bus-m. */ full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang */ flow_ctrl:1, /* Use 802.3x flow control (PAUSE only) */ @@ -1633,12 +1633,6 @@ vortex_set_duplex(struct net_device *dev) ((vp->full_duplex && vp->flow_ctrl && vp->partner_flow_ctrl) ? 0x100 : 0), ioaddr + Wn3_MAC_Ctrl); - - issue_and_wait(dev, TxReset); - /* - * Don't reset the PHY - that upsets autonegotiation during DHCP operations. - */ - issue_and_wait(dev, RxReset|0x04); } static void vortex_check_media(struct net_device *dev, unsigned int init) @@ -1663,7 +1657,7 @@ vortex_up(struct net_device *dev) struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; unsigned int config; - int i; + int i, mii_reg1, mii_reg5; if (VORTEX_PCI(vp)) { pci_set_power_state(VORTEX_PCI(vp), PCI_D0); /* Go active */ @@ -1723,14 +1717,23 @@ vortex_up(struct net_device *dev) printk(KERN_DEBUG "vortex_up(): writing 0x%x to InternalConfig\n", config); iowrite32(config, ioaddr + Wn3_Config); - netif_carrier_off(dev); if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) { EL3WINDOW(4); + mii_reg1 = mdio_read(dev, vp->phys[0], MII_BMSR); + mii_reg5 = mdio_read(dev, vp->phys[0], MII_LPA); + vp->partner_flow_ctrl = ((mii_reg5 & 0x0400) != 0); + vortex_check_media(dev, 1); } else vortex_set_duplex(dev); + issue_and_wait(dev, TxReset); + /* + * Don't reset the PHY - that upsets autonegotiation during DHCP operations. + */ + issue_and_wait(dev, RxReset|0x04); + iowrite16(SetStatusEnb | 0x00, ioaddr + EL3_CMD); -- cgit v1.2.3