diff options
Diffstat (limited to 'drivers/staging/bcm')
54 files changed, 22713 insertions, 0 deletions
diff --git a/drivers/staging/bcm/Adapter.h b/drivers/staging/bcm/Adapter.h new file mode 100644 index 00000000000..1b2d9f3bd55 --- /dev/null +++ b/drivers/staging/bcm/Adapter.h @@ -0,0 +1,457 @@ +/*********************************** +* Adapter.h +************************************/ +#ifndef __ADAPTER_H__ +#define __ADAPTER_H__ + +#define MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES 256 +#include "Debug.h" + +struct bcm_leader { + USHORT Vcid; + USHORT PLength; + UCHAR Status; + UCHAR Unused[3]; +} __packed; + +struct bcm_packettosend { + struct bcm_leader Leader; + UCHAR ucPayload; +} __packed; + +struct bcm_control_packet { + PVOID ControlBuff; + UINT ControlBuffLen; + struct bcm_control_packet *next; +} __packed; + +struct bcm_link_request { + struct bcm_leader Leader; + UCHAR szData[4]; +} __packed; + +#define MAX_IP_RANGE_LENGTH 4 +#define MAX_PORT_RANGE 4 +#define MAX_PROTOCOL_LENGTH 32 +#define IPV6_ADDRESS_SIZEINBYTES 0x10 + +union u_ip_address { + struct { + /* Source Ip Address Range */ + ULONG ulIpv4Addr[MAX_IP_RANGE_LENGTH]; + /* Source Ip Mask Address Range */ + ULONG ulIpv4Mask[MAX_IP_RANGE_LENGTH]; + }; + struct { + ULONG ulIpv6Addr[MAX_IP_RANGE_LENGTH * 4]; /* Source Ip Address Range */ + ULONG ulIpv6Mask[MAX_IP_RANGE_LENGTH * 4]; /* Source Ip Mask Address Range */ + }; + struct { + UCHAR ucIpv4Address[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS]; + UCHAR ucIpv4Mask[MAX_IP_RANGE_LENGTH * IP_LENGTH_OF_ADDRESS]; + }; + struct { + UCHAR ucIpv6Address[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES]; + UCHAR ucIpv6Mask[MAX_IP_RANGE_LENGTH * IPV6_ADDRESS_SIZEINBYTES]; + }; +}; + +struct bcm_hdr_suppression_contextinfo { + UCHAR ucaHdrSuppressionInBuf[MAX_PHS_LENGTHS]; /* Intermediate buffer to accumulate pkt Header for PHS */ + UCHAR ucaHdrSuppressionOutBuf[MAX_PHS_LENGTHS + PHSI_LEN]; /* Intermediate buffer containing pkt Header after PHS */ +}; + +struct bcm_classifier_rule { + ULONG ulSFID; + UCHAR ucReserved[2]; + B_UINT16 uiClassifierRuleIndex; + bool bUsed; + USHORT usVCID_Value; + B_UINT8 u8ClassifierRulePriority; /* This field detemines the Classifier Priority */ + union u_ip_address stSrcIpAddress; + UCHAR ucIPSourceAddressLength; /* Ip Source Address Length */ + + union u_ip_address stDestIpAddress; + UCHAR ucIPDestinationAddressLength; /* Ip Destination Address Length */ + UCHAR ucIPTypeOfServiceLength; /* Type of service Length */ + UCHAR ucTosLow; /* Tos Low */ + UCHAR ucTosHigh; /* Tos High */ + UCHAR ucTosMask; /* Tos Mask */ + + UCHAR ucProtocolLength; /* protocol Length */ + UCHAR ucProtocol[MAX_PROTOCOL_LENGTH]; /* protocol Length */ + USHORT usSrcPortRangeLo[MAX_PORT_RANGE]; + USHORT usSrcPortRangeHi[MAX_PORT_RANGE]; + UCHAR ucSrcPortRangeLength; + + USHORT usDestPortRangeLo[MAX_PORT_RANGE]; + USHORT usDestPortRangeHi[MAX_PORT_RANGE]; + UCHAR ucDestPortRangeLength; + + bool bProtocolValid; + bool bTOSValid; + bool bDestIpValid; + bool bSrcIpValid; + + /* For IPv6 Addressing */ + UCHAR ucDirection; + bool bIpv6Protocol; + UINT32 u32PHSRuleID; + struct bcm_phs_rule sPhsRule; + UCHAR u8AssociatedPHSI; + + /* Classification fields for ETH CS */ + UCHAR ucEthCSSrcMACLen; + UCHAR au8EThCSSrcMAC[MAC_ADDRESS_SIZE]; + UCHAR au8EThCSSrcMACMask[MAC_ADDRESS_SIZE]; + UCHAR ucEthCSDestMACLen; + UCHAR au8EThCSDestMAC[MAC_ADDRESS_SIZE]; + UCHAR au8EThCSDestMACMask[MAC_ADDRESS_SIZE]; + UCHAR ucEtherTypeLen; + UCHAR au8EthCSEtherType[NUM_ETHERTYPE_BYTES]; + UCHAR usUserPriority[2]; + USHORT usVLANID; + USHORT usValidityBitMap; +}; + +struct bcm_fragmented_packet_info { + bool bUsed; + ULONG ulSrcIpAddress; + USHORT usIpIdentification; + struct bcm_classifier_rule *pstMatchedClassifierEntry; + bool bOutOfOrderFragment; +}; + +struct bcm_packet_info { + /* classification extension Rule */ + ULONG ulSFID; + USHORT usVCID_Value; + UINT uiThreshold; + /* This field determines the priority of the SF Queues */ + B_UINT8 u8TrafficPriority; + + bool bValid; + bool bActive; + bool bActivateRequestSent; + + B_UINT8 u8QueueType; /* BE or rtPS */ + + UINT uiMaxBucketSize; /* maximum size of the bucket for the queue */ + UINT uiCurrentQueueDepthOnTarget; + UINT uiCurrentBytesOnHost; + UINT uiCurrentPacketsOnHost; + UINT uiDroppedCountBytes; + UINT uiDroppedCountPackets; + UINT uiSentBytes; + UINT uiSentPackets; + UINT uiCurrentDrainRate; + UINT uiThisPeriodSentBytes; + LARGE_INTEGER liDrainCalculated; + UINT uiCurrentTokenCount; + LARGE_INTEGER liLastUpdateTokenAt; + UINT uiMaxAllowedRate; + UINT NumOfPacketsSent; + UCHAR ucDirection; + USHORT usCID; + struct bcm_mibs_parameters stMibsExtServiceFlowTable; + UINT uiCurrentRxRate; + UINT uiThisPeriodRxBytes; + UINT uiTotalRxBytes; + UINT uiTotalTxBytes; + UINT uiPendedLast; + UCHAR ucIpVersion; + + union { + struct { + struct sk_buff *FirstTxQueue; + struct sk_buff *LastTxQueue; + }; + struct { + struct sk_buff *ControlHead; + struct sk_buff *ControlTail; + }; + }; + + bool bProtocolValid; + bool bTOSValid; + bool bDestIpValid; + bool bSrcIpValid; + + bool bActiveSet; + bool bAdmittedSet; + bool bAuthorizedSet; + bool bClassifierPriority; + UCHAR ucServiceClassName[MAX_CLASS_NAME_LENGTH]; + bool bHeaderSuppressionEnabled; + spinlock_t SFQueueLock; + void *pstSFIndication; + struct timeval stLastUpdateTokenAt; + atomic_t uiPerSFTxResourceCount; + UINT uiMaxLatency; + UCHAR bIPCSSupport; + UCHAR bEthCSSupport; +}; + +struct bcm_tarang_data { + struct bcm_tarang_data *next; + struct bcm_mini_adapter *Adapter; + struct sk_buff *RxAppControlHead; + struct sk_buff *RxAppControlTail; + int AppCtrlQueueLen; + bool MacTracingEnabled; + bool bApplicationToExit; + struct bcm_mibs_dropped_cntrl_msg stDroppedAppCntrlMsgs; + ULONG RxCntrlMsgBitMask; +}; + +struct bcm_targetdsx_buffer { + ULONG ulTargetDsxBuffer; + B_UINT16 tid; + bool valid; +}; + +typedef int (*FP_FLASH_WRITE)(struct bcm_mini_adapter *, UINT, PVOID); + +typedef int (*FP_FLASH_WRITE_STATUS)(struct bcm_mini_adapter *, UINT, PVOID); + +/* + * Driver adapter data structure + */ +struct bcm_mini_adapter { + struct bcm_mini_adapter *next; + struct net_device *dev; + u32 msg_enable; + CHAR *caDsxReqResp; + atomic_t ApplicationRunning; + bool AppCtrlQueueOverFlow; + atomic_t CurrentApplicationCount; + atomic_t RegisteredApplicationCount; + bool LinkUpStatus; + bool TimerActive; + u32 StatisticsPointer; + struct sk_buff *RxControlHead; + struct sk_buff *RxControlTail; + struct semaphore RxAppControlQueuelock; + struct semaphore fw_download_sema; + struct bcm_tarang_data *pTarangs; + spinlock_t control_queue_lock; + wait_queue_head_t process_read_wait_queue; + + /* the pointer to the first packet we have queued in send + * deserialized miniport support variables + */ + atomic_t TotalPacketCount; + atomic_t TxPktAvail; + + /* this to keep track of the Tx and Rx MailBox Registers. */ + atomic_t CurrNumFreeTxDesc; + /* to keep track the no of byte received */ + USHORT PrevNumRecvDescs; + USHORT CurrNumRecvDescs; + UINT u32TotalDSD; + struct bcm_packet_info PackInfo[NO_OF_QUEUES]; + struct bcm_classifier_rule astClassifierTable[MAX_CLASSIFIERS]; + bool TransferMode; + + /*************** qos ******************/ + bool bETHCSEnabled; + ULONG BEBucketSize; + ULONG rtPSBucketSize; + UCHAR LinkStatus; + bool AutoLinkUp; + bool AutoSyncup; + + int major; + int minor; + wait_queue_head_t tx_packet_wait_queue; + wait_queue_head_t process_rx_cntrlpkt; + atomic_t process_waiting; + bool fw_download_done; + + char *txctlpacket[MAX_CNTRL_PKTS]; + atomic_t cntrlpktCnt; + atomic_t index_app_read_cntrlpkt; + atomic_t index_wr_txcntrlpkt; + atomic_t index_rd_txcntrlpkt; + UINT index_datpkt; + struct semaphore rdmwrmsync; + + struct bcm_targetdsx_buffer astTargetDsxBuffer[MAX_TARGET_DSX_BUFFERS]; + ULONG ulFreeTargetBufferCnt; + ULONG ulCurrentTargetBuffer; + ULONG ulTotalTargetBuffersAvailable; + unsigned long chip_id; + wait_queue_head_t lowpower_mode_wait_queue; + bool bFlashBoot; + bool bBinDownloaded; + bool bCfgDownloaded; + bool bSyncUpRequestSent; + USHORT usBestEffortQueueIndex; + wait_queue_head_t ioctl_fw_dnld_wait_queue; + bool waiting_to_fw_download_done; + pid_t fw_download_process_pid; + struct bcm_target_params *pstargetparams; + bool device_removed; + bool DeviceAccess; + bool bIsAutoCorrectEnabled; + bool bDDRInitDone; + int DDRSetting; + ULONG ulPowerSaveMode; + spinlock_t txtransmitlock; + B_UINT8 txtransmit_running; + /* Thread for control packet handling */ + struct task_struct *control_packet_handler; + /* thread for transmitting packets. */ + struct task_struct *transmit_packet_thread; + + /* LED Related Structures */ + struct bcm_led_info LEDInfo; + + /* Driver State for LED Blinking */ + enum bcm_led_events DriverState; + /* Interface Specific */ + PVOID pvInterfaceAdapter; + int (*bcm_file_download)(PVOID, + struct file *, + unsigned int); + int (*bcm_file_readback_from_chip)(PVOID, + struct file *, + unsigned int); + int (*interface_rdm)(PVOID, + UINT, + PVOID, + int); + int (*interface_wrm)(PVOID, + UINT, + PVOID, + int); + int (*interface_transmit)(PVOID, PVOID , UINT); + bool IdleMode; + bool bDregRequestSentInIdleMode; + bool bTriedToWakeUpFromlowPowerMode; + bool bShutStatus; + bool bWakeUpDevice; + unsigned int usIdleModePattern; + /* BOOLEAN bTriedToWakeUpFromShutdown; */ + bool bLinkDownRequested; + int downloadDDR; + struct bcm_phs_extension stBCMPhsContext; + struct bcm_hdr_suppression_contextinfo stPhsTxContextInfo; + uint8_t ucaPHSPktRestoreBuf[2048]; + uint8_t bPHSEnabled; + bool AutoFirmDld; + bool bMipsConfig; + bool bDPLLConfig; + UINT32 aTxPktSizeHist[MIBS_MAX_HIST_ENTRIES]; + UINT32 aRxPktSizeHist[MIBS_MAX_HIST_ENTRIES]; + struct bcm_fragmented_packet_info astFragmentedPktClassifierTable[MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES]; + atomic_t uiMBupdate; + UINT32 PmuMode; + enum bcm_nvm_type eNVMType; + UINT uiSectorSize; + UINT uiSectorSizeInCFG; + bool bSectorSizeOverride; + bool bStatusWrite; + UINT uiNVMDSDSize; + UINT uiVendorExtnFlag; + /* it will always represent chosen DSD at any point of time. + * Generally it is Active DSD but in case of NVM RD/WR it might be different. + */ + UINT ulFlashCalStart; + ULONG ulFlashControlSectionStart; + ULONG ulFlashWriteSize; + ULONG ulFlashID; + FP_FLASH_WRITE fpFlashWrite; + FP_FLASH_WRITE_STATUS fpFlashWriteWithStatusCheck; + + struct semaphore NVMRdmWrmLock; + struct device *pstCreatedClassDevice; + + /* BOOLEAN InterfaceUpStatus; */ + struct bcm_flash2x_cs_info *psFlash2xCSInfo; + struct bcm_flash_cs_info *psFlashCSInfo; + struct bcm_flash2x_vendor_info *psFlash2xVendorInfo; + UINT uiFlashBaseAdd; /* Flash start address */ + UINT uiActiveISOOffset; /* Active ISO offset chosen before f/w download */ + enum bcm_flash2x_section_val eActiveISO; /* Active ISO section val */ + enum bcm_flash2x_section_val eActiveDSD; /* Active DSD val chosen before f/w download */ + UINT uiActiveDSDOffsetAtFwDld; /* For accessing Active DSD chosen before f/w download */ + UINT uiFlashLayoutMajorVersion; + UINT uiFlashLayoutMinorVersion; + bool bAllDSDWriteAllow; + bool bSigCorrupted; + /* this should be set who so ever want to change the Headers. after Write it should be reset immediately. */ + bool bHeaderChangeAllowed; + int SelectedChip; + bool bEndPointHalted; + /* while bFlashRawRead will be true, Driver ignore map lay out and consider flash as of without any map. */ + bool bFlashRawRead; + bool bPreparingForLowPowerMode; + bool bDoSuspend; + UINT syscfgBefFwDld; + bool StopAllXaction; + UINT32 liTimeSinceLastNetEntry; /* Used to Support extended CAPI requirements from */ + struct semaphore LowPowerModeSync; + ULONG liDrainCalculated; + UINT gpioBitMap; + struct bcm_debug_state stDebugState; +}; + +#define GET_BCM_ADAPTER(net_dev) netdev_priv(net_dev) + +struct bcm_eth_header { + UCHAR au8DestinationAddress[6]; + UCHAR au8SourceAddress[6]; + USHORT u16Etype; +} __packed; + +struct bcm_firmware_info { + void __user *pvMappedFirmwareAddress; + ULONG u32FirmwareLength; + ULONG u32StartingAddress; +} __packed; + +/* holds the value of net_device structure.. */ +extern struct net_device *gblpnetdev; + +struct bcm_ddr_setting { + UINT ulRegAddress; + UINT ulRegValue; +}; +int InitAdapter(struct bcm_mini_adapter *psAdapter); + +/* ===================================================================== + * Beceem vendor request codes for EP0 + * ===================================================================== + */ + +#define BCM_REQUEST_READ 0x2 +#define BCM_REQUEST_WRITE 0x1 +#define EP2_MPS_REG 0x0F0110A0 +#define EP2_MPS 0x40 + +#define EP2_CFG_REG 0x0F0110A8 +#define EP2_CFG_INT 0x27 +#define EP2_CFG_BULK 0x25 + +#define EP4_MPS_REG 0x0F0110F0 +#define EP4_MPS 0x8C + +#define EP4_CFG_REG 0x0F0110F8 + +#define ISO_MPS_REG 0x0F0110C8 +#define ISO_MPS 0x00000000 + +#define EP1 0 +#define EP2 1 +#define EP3 2 +#define EP4 3 +#define EP5 4 +#define EP6 5 + +enum bcm_einterface_setting { + DEFAULT_SETTING_0 = 0, + ALTERNATE_SETTING_1 = 1, +}; + +#endif /* __ADAPTER_H__ */ diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c new file mode 100644 index 00000000000..606d5f5e921 --- /dev/null +++ b/drivers/staging/bcm/Bcmchar.c @@ -0,0 +1,2652 @@ +#include <linux/fs.h> + +#include "headers.h" + +static int bcm_handle_nvm_read_cmd(struct bcm_mini_adapter *Adapter, + PUCHAR pReadData, struct bcm_nvm_readwrite *stNVMReadWrite) +{ + INT Status = STATUS_FAILURE; + + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadData); + return -EACCES; + } + + Status = BeceemNVMRead(Adapter, (PUINT)pReadData, + stNVMReadWrite->uiOffset, + stNVMReadWrite->uiNumBytes); + up(&Adapter->NVMRdmWrmLock); + + if (Status != STATUS_SUCCESS) { + kfree(pReadData); + return Status; + } + + if (copy_to_user(stNVMReadWrite->pBuffer, pReadData, + stNVMReadWrite->uiNumBytes)) { + kfree(pReadData); + return -EFAULT; + } + + return STATUS_SUCCESS; +} + +static int handle_flash2x_adapter(struct bcm_mini_adapter *Adapter, + PUCHAR pReadData, struct bcm_nvm_readwrite *stNVMReadWrite) +{ + /* + * New Requirement:- + * DSD section updation will be allowed in two case:- + * 1. if DSD sig is present in DSD header means dongle + * is ok and updation is fruitfull + * 2. if point 1 failes then user buff should have + * DSD sig. this point ensures that if dongle is + * corrupted then user space program first modify + * the DSD header with valid DSD sig so that this + * as well as further write may be worthwhile. + * + * This restriction has been put assuming that + * if DSD sig is corrupted, DSD data won't be + * considered valid. + */ + INT Status; + ULONG ulDSDMagicNumInUsrBuff = 0; + + Status = BcmFlash2xCorruptSig(Adapter, Adapter->eActiveDSD); + if (Status == STATUS_SUCCESS) + return STATUS_SUCCESS; + + if (((stNVMReadWrite->uiOffset + stNVMReadWrite->uiNumBytes) != + Adapter->uiNVMDSDSize) || + (stNVMReadWrite->uiNumBytes < SIGNATURE_SIZE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "DSD Sig is present neither in Flash nor User provided Input.."); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadData); + return Status; + } + + ulDSDMagicNumInUsrBuff = + ntohl(*(PUINT)(pReadData + stNVMReadWrite->uiNumBytes - + SIGNATURE_SIZE)); + if (ulDSDMagicNumInUsrBuff != DSD_IMAGE_MAGIC_NUMBER) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "DSD Sig is present neither in Flash nor User provided Input.."); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadData); + return Status; + } + + return STATUS_SUCCESS; +} + +/*************************************************************** +* Function - bcm_char_open() +* +* Description - This is the "open" entry point for the character +* driver. +* +* Parameters - inode: Pointer to the Inode structure of char device +* filp : File pointer of the char device +* +* Returns - Zero(Success) +****************************************************************/ + +static int bcm_char_open(struct inode *inode, struct file *filp) +{ + struct bcm_mini_adapter *Adapter = NULL; + struct bcm_tarang_data *pTarang = NULL; + + Adapter = GET_BCM_ADAPTER(gblpnetdev); + pTarang = kzalloc(sizeof(struct bcm_tarang_data), GFP_KERNEL); + if (!pTarang) + return -ENOMEM; + + pTarang->Adapter = Adapter; + pTarang->RxCntrlMsgBitMask = 0xFFFFFFFF & ~(1 << 0xB); + + down(&Adapter->RxAppControlQueuelock); + pTarang->next = Adapter->pTarangs; + Adapter->pTarangs = pTarang; + up(&Adapter->RxAppControlQueuelock); + + /* Store the Adapter structure */ + filp->private_data = pTarang; + + /* Start Queuing the control response Packets */ + atomic_inc(&Adapter->ApplicationRunning); + + nonseekable_open(inode, filp); + return 0; +} + +static int bcm_char_release(struct inode *inode, struct file *filp) +{ + struct bcm_tarang_data *pTarang, *tmp, *ptmp; + struct bcm_mini_adapter *Adapter = NULL; + struct sk_buff *pkt, *npkt; + + pTarang = (struct bcm_tarang_data *)filp->private_data; + + if (pTarang == NULL) + return 0; + + Adapter = pTarang->Adapter; + + down(&Adapter->RxAppControlQueuelock); + + tmp = Adapter->pTarangs; + for (ptmp = NULL; tmp; ptmp = tmp, tmp = tmp->next) { + if (tmp == pTarang) + break; + } + + if (tmp) { + if (!ptmp) + Adapter->pTarangs = tmp->next; + else + ptmp->next = tmp->next; + } else { + up(&Adapter->RxAppControlQueuelock); + return 0; + } + + pkt = pTarang->RxAppControlHead; + while (pkt) { + npkt = pkt->next; + kfree_skb(pkt); + pkt = npkt; + } + + up(&Adapter->RxAppControlQueuelock); + + /* Stop Queuing the control response Packets */ + atomic_dec(&Adapter->ApplicationRunning); + + kfree(pTarang); + + /* remove this filp from the asynchronously notified filp's */ + filp->private_data = NULL; + return 0; +} + +static ssize_t bcm_char_read(struct file *filp, char __user *buf, size_t size, + loff_t *f_pos) +{ + struct bcm_tarang_data *pTarang = filp->private_data; + struct bcm_mini_adapter *Adapter = pTarang->Adapter; + struct sk_buff *Packet = NULL; + ssize_t PktLen = 0; + int wait_ret_val = 0; + unsigned long ret = 0; + + wait_ret_val = wait_event_interruptible( + Adapter->process_read_wait_queue, + (pTarang->RxAppControlHead || + Adapter->device_removed)); + + if ((wait_ret_val == -ERESTARTSYS)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Exiting as i've been asked to exit!!!\n"); + return wait_ret_val; + } + + if (Adapter->device_removed) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device Removed... Killing the Apps...\n"); + return -ENODEV; + } + + if (false == Adapter->fw_download_done) + return -EACCES; + + down(&Adapter->RxAppControlQueuelock); + + if (pTarang->RxAppControlHead) { + Packet = pTarang->RxAppControlHead; + DEQUEUEPACKET(pTarang->RxAppControlHead, + pTarang->RxAppControlTail); + pTarang->AppCtrlQueueLen--; + } + + up(&Adapter->RxAppControlQueuelock); + + if (Packet) { + PktLen = Packet->len; + ret = copy_to_user(buf, Packet->data, + min_t(size_t, PktLen, size)); + if (ret) { + dev_kfree_skb(Packet); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Returning from copy to user failure\n"); + return -EFAULT; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Read %zd Bytes From Adapter packet = %p by process %d!\n", + PktLen, Packet, current->pid); + dev_kfree_skb(Packet); + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, "<\n"); + return PktLen; +} + +static int bcm_char_ioctl_reg_read_private(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_rdm_buffer sRdmBuffer = {0}; + struct bcm_ioctl_buffer IoBuffer; + PCHAR temp_buff; + INT Status = STATUS_FAILURE; + UINT Bufflen; + u16 temp_value; + int bytes; + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(sRdmBuffer)) + return -EINVAL; + + if (copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + if (IoBuffer.OutputLength > USHRT_MAX || + IoBuffer.OutputLength == 0) { + return -EINVAL; + } + + Bufflen = IoBuffer.OutputLength; + temp_value = 4 - (Bufflen % 4); + Bufflen += temp_value % 4; + + temp_buff = kmalloc(Bufflen, GFP_KERNEL); + if (!temp_buff) + return -ENOMEM; + + bytes = rdmalt(Adapter, (UINT)sRdmBuffer.Register, + (PUINT)temp_buff, Bufflen); + if (bytes > 0) { + Status = STATUS_SUCCESS; + if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) { + kfree(temp_buff); + return -EFAULT; + } + } else { + Status = bytes; + } + + kfree(temp_buff); + return Status; +} + +static int bcm_char_ioctl_reg_write_private(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_wrm_buffer sWrmBuffer = {0}; + struct bcm_ioctl_buffer IoBuffer; + UINT uiTempVar = 0; + INT Status; + + /* Copy Ioctl Buffer structure */ + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(sWrmBuffer)) + return -EINVAL; + + /* Get WrmBuffer structure */ + if (copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK; + if (!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) && + ((uiTempVar == EEPROM_REJECT_REG_1) || + (uiTempVar == EEPROM_REJECT_REG_2) || + (uiTempVar == EEPROM_REJECT_REG_3) || + (uiTempVar == EEPROM_REJECT_REG_4))) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "EEPROM Access Denied, not in VSG Mode\n"); + return -EFAULT; + } + + Status = wrmalt(Adapter, (UINT)sWrmBuffer.Register, + (PUINT)sWrmBuffer.Data, sizeof(ULONG)); + + if (Status == STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "WRM Done\n"); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "WRM Failed\n"); + Status = -EFAULT; + } + return Status; +} + +static int bcm_char_ioctl_eeprom_reg_read(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_rdm_buffer sRdmBuffer = {0}; + struct bcm_ioctl_buffer IoBuffer; + PCHAR temp_buff = NULL; + UINT uiTempVar = 0; + INT Status; + int bytes; + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Device in Idle Mode, Blocking Rdms\n"); + return -EACCES; + } + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(sRdmBuffer)) + return -EINVAL; + + if (copy_from_user(&sRdmBuffer, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + if (IoBuffer.OutputLength > USHRT_MAX || + IoBuffer.OutputLength == 0) { + return -EINVAL; + } + + temp_buff = kmalloc(IoBuffer.OutputLength, GFP_KERNEL); + if (!temp_buff) + return STATUS_FAILURE; + + if ((((ULONG)sRdmBuffer.Register & 0x0F000000) != 0x0F000000) || + ((ULONG)sRdmBuffer.Register & 0x3)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "RDM Done On invalid Address : %x Access Denied.\n", + (int)sRdmBuffer.Register); + + kfree(temp_buff); + return -EINVAL; + } + + uiTempVar = sRdmBuffer.Register & EEPROM_REJECT_MASK; + bytes = rdmaltWithLock(Adapter, (UINT)sRdmBuffer.Register, + (PUINT)temp_buff, IoBuffer.OutputLength); + + if (bytes > 0) { + Status = STATUS_SUCCESS; + if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, bytes)) { + kfree(temp_buff); + return -EFAULT; + } + } else { + Status = bytes; + } + + kfree(temp_buff); + return Status; +} + +static int bcm_char_ioctl_eeprom_reg_write(void __user *argp, + struct bcm_mini_adapter *Adapter, + UINT cmd) +{ + struct bcm_wrm_buffer sWrmBuffer = {0}; + struct bcm_ioctl_buffer IoBuffer; + UINT uiTempVar = 0; + INT Status; + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Device in Idle Mode, Blocking Wrms\n"); + return -EACCES; + } + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(sWrmBuffer)) + return -EINVAL; + + /* Get WrmBuffer structure */ + if (copy_from_user(&sWrmBuffer, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + if ((((ULONG)sWrmBuffer.Register & 0x0F000000) != 0x0F000000) || + ((ULONG)sWrmBuffer.Register & 0x3)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "WRM Done On invalid Address : %x Access Denied.\n", + (int)sWrmBuffer.Register); + return -EINVAL; + } + + uiTempVar = sWrmBuffer.Register & EEPROM_REJECT_MASK; + if (!((Adapter->pstargetparams->m_u32Customize) & VSG_MODE) && + ((uiTempVar == EEPROM_REJECT_REG_1) || + (uiTempVar == EEPROM_REJECT_REG_2) || + (uiTempVar == EEPROM_REJECT_REG_3) || + (uiTempVar == EEPROM_REJECT_REG_4)) && + (cmd == IOCTL_BCM_REGISTER_WRITE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "EEPROM Access Denied, not in VSG Mode\n"); + return -EFAULT; + } + + Status = wrmaltWithLock(Adapter, (UINT)sWrmBuffer.Register, + (PUINT)sWrmBuffer.Data, + sWrmBuffer.Length); + + if (Status == STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, OSAL_DBG, + DBG_LVL_ALL, "WRM Done\n"); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "WRM Failed\n"); + Status = -EFAULT; + } + return Status; +} + +static int bcm_char_ioctl_gpio_set_request(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_gpio_info gpio_info = {0}; + struct bcm_ioctl_buffer IoBuffer; + UCHAR ucResetValue[4]; + UINT value = 0; + UINT uiBit = 0; + UINT uiOperation = 0; + INT Status; + int bytes; + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, + "GPIO Can't be set/clear in Low power Mode"); + return -EACCES; + } + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(gpio_info)) + return -EINVAL; + + if (copy_from_user(&gpio_info, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + uiBit = gpio_info.uiGpioNumber; + uiOperation = gpio_info.uiGpioValue; + value = (1<<uiBit); + + if (IsReqGpioIsLedInNVM(Adapter, value) == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, + "Sorry, Requested GPIO<0x%X> is not correspond to LED !!!", + value); + return -EINVAL; + } + + /* Set - setting 1 */ + if (uiOperation) { + /* Set the gpio output register */ + Status = wrmaltWithLock(Adapter, + BCM_GPIO_OUTPUT_SET_REG, + (PUINT)(&value), sizeof(UINT)); + + if (Status == STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, + "Set the GPIO bit\n"); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, + "Failed to set the %dth GPIO\n", + uiBit); + return Status; + } + } else { + /* Set the gpio output register */ + Status = wrmaltWithLock(Adapter, + BCM_GPIO_OUTPUT_CLR_REG, + (PUINT)(&value), sizeof(UINT)); + + if (Status == STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, + "Set the GPIO bit\n"); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, + "Failed to clear the %dth GPIO\n", + uiBit); + return Status; + } + } + + bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER, + (PUINT)ucResetValue, sizeof(UINT)); + if (bytes < 0) { + Status = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "GPIO_MODE_REGISTER read failed"); + return Status; + } else { + Status = STATUS_SUCCESS; + } + + /* Set the gpio mode register to output */ + *(UINT *)ucResetValue |= (1<<uiBit); + Status = wrmaltWithLock(Adapter, GPIO_MODE_REGISTER, + (PUINT)ucResetValue, sizeof(UINT)); + + if (Status == STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, + "Set the GPIO to output Mode\n"); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, + "Failed to put GPIO in Output Mode\n"); + } + + return Status; +} + +static int bcm_char_ioctl_led_thread_state_change_req(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_user_thread_req threadReq = {0}; + struct bcm_ioctl_buffer IoBuffer; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "User made LED thread InActive"); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, + "GPIO Can't be set/clear in Low power Mode"); + return -EACCES; + } + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(threadReq)) + return -EINVAL; + + if (copy_from_user(&threadReq, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + /* if LED thread is running(Actively or Inactively) + * set it state to make inactive + */ + if (Adapter->LEDInfo.led_thread_running) { + if (threadReq.ThreadState == LED_THREAD_ACTIVATION_REQ) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, + "Activating thread req"); + Adapter->DriverState = LED_THREAD_ACTIVE; + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, + "DeActivating Thread req....."); + Adapter->DriverState = LED_THREAD_INACTIVE; + } + + /* signal thread. */ + wake_up(&Adapter->LEDInfo.notify_led_event); + } + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_gpio_status_request(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_gpio_info gpio_info = {0}; + struct bcm_ioctl_buffer IoBuffer; + ULONG uiBit = 0; + UCHAR ucRead[4]; + INT Status; + int bytes; + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) + return -EACCES; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(gpio_info)) + return -EINVAL; + + if (copy_from_user(&gpio_info, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + uiBit = gpio_info.uiGpioNumber; + + /* Set the gpio output register */ + bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER, + (PUINT)ucRead, sizeof(UINT)); + + if (bytes < 0) { + Status = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "RDM Failed\n"); + return Status; + } else { + Status = STATUS_SUCCESS; + } + return Status; +} + +static int bcm_char_ioctl_gpio_multi_request(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_gpio_multi_info gpio_multi_info[MAX_IDX]; + struct bcm_gpio_multi_info *pgpio_multi_info = + (struct bcm_gpio_multi_info *)gpio_multi_info; + struct bcm_ioctl_buffer IoBuffer; + UCHAR ucResetValue[4]; + INT Status = STATUS_FAILURE; + int bytes; + + memset(pgpio_multi_info, 0, + MAX_IDX * sizeof(struct bcm_gpio_multi_info)); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) + return -EINVAL; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(gpio_multi_info)) + return -EINVAL; + if (IoBuffer.OutputLength > sizeof(gpio_multi_info)) + IoBuffer.OutputLength = sizeof(gpio_multi_info); + + if (copy_from_user(&gpio_multi_info, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + if (IsReqGpioIsLedInNVM(Adapter, pgpio_multi_info[WIMAX_IDX].uiGPIOMask) + == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, + "Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!", + pgpio_multi_info[WIMAX_IDX].uiGPIOMask, + Adapter->gpioBitMap); + return -EINVAL; + } + + /* Set the gpio output register */ + if ((pgpio_multi_info[WIMAX_IDX].uiGPIOMask) & + (pgpio_multi_info[WIMAX_IDX].uiGPIOCommand)) { + /* Set 1's in GPIO OUTPUT REGISTER */ + *(UINT *)ucResetValue = pgpio_multi_info[WIMAX_IDX].uiGPIOMask & + pgpio_multi_info[WIMAX_IDX].uiGPIOCommand & + pgpio_multi_info[WIMAX_IDX].uiGPIOValue; + + if (*(UINT *) ucResetValue) + Status = wrmaltWithLock(Adapter, + BCM_GPIO_OUTPUT_SET_REG, + (PUINT)ucResetValue, sizeof(ULONG)); + + if (Status != STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "WRM to BCM_GPIO_OUTPUT_SET_REG Failed."); + return Status; + } + + /* Clear to 0's in GPIO OUTPUT REGISTER */ + *(UINT *)ucResetValue = + (pgpio_multi_info[WIMAX_IDX].uiGPIOMask & + pgpio_multi_info[WIMAX_IDX].uiGPIOCommand & + (~(pgpio_multi_info[WIMAX_IDX].uiGPIOValue))); + + if (*(UINT *) ucResetValue) + Status = wrmaltWithLock(Adapter, + BCM_GPIO_OUTPUT_CLR_REG, (PUINT)ucResetValue, + sizeof(ULONG)); + + if (Status != STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "WRM to BCM_GPIO_OUTPUT_CLR_REG Failed."); + return Status; + } + } + + if (pgpio_multi_info[WIMAX_IDX].uiGPIOMask) { + bytes = rdmaltWithLock(Adapter, (UINT)GPIO_PIN_STATE_REGISTER, + (PUINT)ucResetValue, sizeof(UINT)); + + if (bytes < 0) { + Status = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "RDM to GPIO_PIN_STATE_REGISTER Failed."); + return Status; + } else { + Status = STATUS_SUCCESS; + } + + pgpio_multi_info[WIMAX_IDX].uiGPIOValue = + (*(UINT *)ucResetValue & + pgpio_multi_info[WIMAX_IDX].uiGPIOMask); + } + + Status = copy_to_user(IoBuffer.OutputBuffer, &gpio_multi_info, + IoBuffer.OutputLength); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Failed while copying Content to IOBufer for user space err:%d", + Status); + return -EFAULT; + } + return Status; +} + +static int bcm_char_ioctl_gpio_mode_request(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_gpio_multi_mode gpio_multi_mode[MAX_IDX]; + struct bcm_gpio_multi_mode *pgpio_multi_mode = + (struct bcm_gpio_multi_mode *)gpio_multi_mode; + struct bcm_ioctl_buffer IoBuffer; + UCHAR ucResetValue[4]; + INT Status; + int bytes; + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) + return -EINVAL; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength > sizeof(gpio_multi_mode)) + return -EINVAL; + if (IoBuffer.OutputLength > sizeof(gpio_multi_mode)) + IoBuffer.OutputLength = sizeof(gpio_multi_mode); + + if (copy_from_user(&gpio_multi_mode, IoBuffer.InputBuffer, + IoBuffer.InputLength)) + return -EFAULT; + + bytes = rdmaltWithLock(Adapter, (UINT)GPIO_MODE_REGISTER, + (PUINT)ucResetValue, sizeof(UINT)); + + if (bytes < 0) { + Status = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Read of GPIO_MODE_REGISTER failed"); + return Status; + } else { + Status = STATUS_SUCCESS; + } + + /* Validating the request */ + if (IsReqGpioIsLedInNVM(Adapter, pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) + == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Sorry, Requested GPIO<0x%X> is not correspond to NVM LED bit map<0x%X>!!!", + pgpio_multi_mode[WIMAX_IDX].uiGPIOMask, + Adapter->gpioBitMap); + return -EINVAL; + } + + if (pgpio_multi_mode[WIMAX_IDX].uiGPIOMask) { + /* write all OUT's (1's) */ + *(UINT *) ucResetValue |= + (pgpio_multi_mode[WIMAX_IDX].uiGPIOMode & + pgpio_multi_mode[WIMAX_IDX].uiGPIOMask); + + /* write all IN's (0's) */ + *(UINT *) ucResetValue &= + ~((~pgpio_multi_mode[WIMAX_IDX].uiGPIOMode) & + pgpio_multi_mode[WIMAX_IDX].uiGPIOMask); + + /* Currently implemented return the modes of all GPIO's + * else needs to bit AND with mask + */ + pgpio_multi_mode[WIMAX_IDX].uiGPIOMode = *(UINT *)ucResetValue; + + Status = wrmaltWithLock(Adapter, GPIO_MODE_REGISTER, + (PUINT)ucResetValue, sizeof(ULONG)); + if (Status == STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "WRM to GPIO_MODE_REGISTER Done"); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "WRM to GPIO_MODE_REGISTER Failed"); + return -EFAULT; + } + } else { + /* if uiGPIOMask is 0 then return mode register configuration */ + pgpio_multi_mode[WIMAX_IDX].uiGPIOMode = *(UINT *)ucResetValue; + } + + Status = copy_to_user(IoBuffer.OutputBuffer, &gpio_multi_mode, + IoBuffer.OutputLength); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Failed while copying Content to IOBufer for user space err:%d", + Status); + return -EFAULT; + } + return Status; +} + +static int bcm_char_ioctl_misc_request(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + PVOID pvBuffer = NULL; + INT Status; + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength < sizeof(struct bcm_link_request)) + return -EINVAL; + + if (IoBuffer.InputLength > MAX_CNTL_PKT_SIZE) + return -EINVAL; + + pvBuffer = memdup_user(IoBuffer.InputBuffer, + IoBuffer.InputLength); + if (IS_ERR(pvBuffer)) + return PTR_ERR(pvBuffer); + + down(&Adapter->LowPowerModeSync); + Status = wait_event_interruptible_timeout( + Adapter->lowpower_mode_wait_queue, + !Adapter->bPreparingForLowPowerMode, + (1 * HZ)); + + if (Status == -ERESTARTSYS) + goto cntrlEnd; + + if (Adapter->bPreparingForLowPowerMode) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Preparing Idle Mode is still True - Hence Rejecting control message\n"); + Status = STATUS_FAILURE; + goto cntrlEnd; + } + Status = CopyBufferToControlPacket(Adapter, (PVOID)pvBuffer); + +cntrlEnd: + up(&Adapter->LowPowerModeSync); + kfree(pvBuffer); + return Status; +} + +static int bcm_char_ioctl_buffer_download_start( + struct bcm_mini_adapter *Adapter) +{ + INT Status; + + if (down_trylock(&Adapter->NVMRdmWrmLock)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_CHIP_RESET not allowed as EEPROM Read/Write is in progress\n"); + return -EACCES; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Starting the firmware download PID =0x%x!!!!\n", + current->pid); + + if (down_trylock(&Adapter->fw_download_sema)) + return -EBUSY; + + Adapter->bBinDownloaded = false; + Adapter->fw_download_process_pid = current->pid; + Adapter->bCfgDownloaded = false; + Adapter->fw_download_done = false; + netif_carrier_off(Adapter->dev); + netif_stop_queue(Adapter->dev); + Status = reset_card_proc(Adapter); + if (Status) { + pr_err(PFX "%s: reset_card_proc Failed!\n", Adapter->dev->name); + up(&Adapter->fw_download_sema); + up(&Adapter->NVMRdmWrmLock); + return Status; + } + mdelay(10); + + up(&Adapter->NVMRdmWrmLock); + return Status; +} + +static int bcm_char_ioctl_buffer_download(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_firmware_info *psFwInfo = NULL; + struct bcm_ioctl_buffer IoBuffer; + INT Status; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Starting the firmware download PID =0x%x!!!!\n", current->pid); + + if (!down_trylock(&Adapter->fw_download_sema)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Invalid way to download buffer. Use Start and then call this!!!\n"); + up(&Adapter->fw_download_sema); + return -EINVAL; + } + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) { + up(&Adapter->fw_download_sema); + return -EFAULT; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Length for FW DLD is : %lx\n", IoBuffer.InputLength); + + if (IoBuffer.InputLength > sizeof(struct bcm_firmware_info)) { + up(&Adapter->fw_download_sema); + return -EINVAL; + } + + psFwInfo = kmalloc(sizeof(*psFwInfo), GFP_KERNEL); + if (!psFwInfo) { + up(&Adapter->fw_download_sema); + return -ENOMEM; + } + + if (copy_from_user(psFwInfo, IoBuffer.InputBuffer, + IoBuffer.InputLength)) { + up(&Adapter->fw_download_sema); + kfree(psFwInfo); + return -EFAULT; + } + + if (!psFwInfo->pvMappedFirmwareAddress || + (psFwInfo->u32FirmwareLength == 0)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Something else is wrong %lu\n", + psFwInfo->u32FirmwareLength); + up(&Adapter->fw_download_sema); + kfree(psFwInfo); + Status = -EINVAL; + return Status; + } + + Status = bcm_ioctl_fw_download(Adapter, psFwInfo); + + if (Status != STATUS_SUCCESS) { + if (psFwInfo->u32StartingAddress == CONFIG_BEGIN_ADDR) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "IOCTL: Configuration File Upload Failed\n"); + else + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "IOCTL: Firmware File Upload Failed\n"); + + /* up(&Adapter->fw_download_sema); */ + + if (Adapter->LEDInfo.led_thread_running & + BCM_LED_THREAD_RUNNING_ACTIVELY) { + Adapter->DriverState = DRIVER_INIT; + Adapter->LEDInfo.bLedInitDone = false; + wake_up(&Adapter->LEDInfo.notify_led_event); + } + } + + if (Status != STATUS_SUCCESS) + up(&Adapter->fw_download_sema); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, OSAL_DBG, DBG_LVL_ALL, + "IOCTL: Firmware File Uploaded\n"); + kfree(psFwInfo); + return Status; +} + +static int bcm_char_ioctl_buffer_download_stop(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + INT Status; + int timeout = 0; + + if (!down_trylock(&Adapter->fw_download_sema)) { + up(&Adapter->fw_download_sema); + return -EINVAL; + } + + if (down_trylock(&Adapter->NVMRdmWrmLock)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "FW download blocked as EEPROM Read/Write is in progress\n"); + up(&Adapter->fw_download_sema); + return -EACCES; + } + + Adapter->bBinDownloaded = TRUE; + Adapter->bCfgDownloaded = TRUE; + atomic_set(&Adapter->CurrNumFreeTxDesc, 0); + Adapter->CurrNumRecvDescs = 0; + Adapter->downloadDDR = 0; + + /* setting the Mips to Run */ + Status = run_card_proc(Adapter); + + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Firm Download Failed\n"); + up(&Adapter->fw_download_sema); + up(&Adapter->NVMRdmWrmLock); + return Status; + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "Firm Download Over...\n"); + } + + mdelay(10); + + /* Wait for MailBox Interrupt */ + if (StartInterruptUrb((struct bcm_interface_adapter *)Adapter->pvInterfaceAdapter)) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Unable to send interrupt...\n"); + + timeout = 5*HZ; + Adapter->waiting_to_fw_download_done = false; + wait_event_timeout(Adapter->ioctl_fw_dnld_wait_queue, + Adapter->waiting_to_fw_download_done, timeout); + Adapter->fw_download_process_pid = INVALID_PID; + Adapter->fw_download_done = TRUE; + atomic_set(&Adapter->CurrNumFreeTxDesc, 0); + Adapter->CurrNumRecvDescs = 0; + Adapter->PrevNumRecvDescs = 0; + atomic_set(&Adapter->cntrlpktCnt, 0); + Adapter->LinkUpStatus = 0; + Adapter->LinkStatus = 0; + + if (Adapter->LEDInfo.led_thread_running & + BCM_LED_THREAD_RUNNING_ACTIVELY) { + Adapter->DriverState = FW_DOWNLOAD_DONE; + wake_up(&Adapter->LEDInfo.notify_led_event); + } + + if (!timeout) + Status = -ENODEV; + + up(&Adapter->fw_download_sema); + up(&Adapter->NVMRdmWrmLock); + return Status; +} + +static int bcm_char_ioctl_chip_reset(struct bcm_mini_adapter *Adapter) +{ + INT Status; + INT NVMAccess; + + NVMAccess = down_trylock(&Adapter->NVMRdmWrmLock); + if (NVMAccess) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + " IOCTL_BCM_CHIP_RESET not allowed as EEPROM Read/Write is in progress\n"); + return -EACCES; + } + + down(&Adapter->RxAppControlQueuelock); + Status = reset_card_proc(Adapter); + flushAllAppQ(); + up(&Adapter->RxAppControlQueuelock); + up(&Adapter->NVMRdmWrmLock); + ResetCounters(Adapter); + return Status; +} + +static int bcm_char_ioctl_qos_threshold(ULONG arg, + struct bcm_mini_adapter *Adapter) +{ + USHORT uiLoopIndex; + + for (uiLoopIndex = 0; uiLoopIndex < NO_OF_QUEUES; uiLoopIndex++) { + if (get_user(Adapter->PackInfo[uiLoopIndex].uiThreshold, + (unsigned long __user *)arg)) { + return -EFAULT; + } + } + return 0; +} + +static int bcm_char_ioctl_switch_transfer_mode(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + UINT uiData = 0; + + if (copy_from_user(&uiData, argp, sizeof(UINT))) + return -EFAULT; + + if (uiData) { + /* Allow All Packets */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_SWITCH_TRANSFER_MODE: ETH_PACKET_TUNNELING_MODE\n"); + Adapter->TransferMode = ETH_PACKET_TUNNELING_MODE; + } else { + /* Allow IP only Packets */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_SWITCH_TRANSFER_MODE: IP_PACKET_ONLY_MODE\n"); + Adapter->TransferMode = IP_PACKET_ONLY_MODE; + } + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_get_driver_version(void __user *argp) +{ + struct bcm_ioctl_buffer IoBuffer; + ulong len; + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + len = min_t(ulong, IoBuffer.OutputLength, strlen(DRV_VERSION) + 1); + + if (copy_to_user(IoBuffer.OutputBuffer, DRV_VERSION, len)) + return -EFAULT; + + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_get_current_status(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_link_state link_state; + struct bcm_ioctl_buffer IoBuffer; + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "copy_from_user failed..\n"); + return -EFAULT; + } + + if (IoBuffer.OutputLength != sizeof(link_state)) + return -EINVAL; + + memset(&link_state, 0, sizeof(link_state)); + link_state.bIdleMode = Adapter->IdleMode; + link_state.bShutdownMode = Adapter->bShutStatus; + link_state.ucLinkStatus = Adapter->LinkStatus; + + if (copy_to_user(IoBuffer.OutputBuffer, &link_state, min_t(size_t, + sizeof(link_state), IoBuffer.OutputLength))) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy_to_user Failed..\n"); + return -EFAULT; + } + return STATUS_SUCCESS; +} + + +static int bcm_char_ioctl_set_mac_tracing(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + UINT tracing_flag; + + /* copy ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (copy_from_user(&tracing_flag, IoBuffer.InputBuffer, sizeof(UINT))) + return -EFAULT; + + if (tracing_flag) + Adapter->pTarangs->MacTracingEnabled = TRUE; + else + Adapter->pTarangs->MacTracingEnabled = false; + + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_get_dsx_indication(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + ULONG ulSFId = 0; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.OutputLength < sizeof(struct bcm_add_indication_alt)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Mismatch req: %lx needed is =0x%zx!!!", + IoBuffer.OutputLength, + sizeof(struct bcm_add_indication_alt)); + return -EINVAL; + } + + if (copy_from_user(&ulSFId, IoBuffer.InputBuffer, sizeof(ulSFId))) + return -EFAULT; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Get DSX Data SF ID is =%lx\n", ulSFId); + get_dsx_sf_data_to_application(Adapter, ulSFId, IoBuffer.OutputBuffer); + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_get_host_mibs(void __user *argp, + struct bcm_mini_adapter *Adapter, struct bcm_tarang_data *pTarang) +{ + struct bcm_ioctl_buffer IoBuffer; + INT Status = STATUS_FAILURE; + PVOID temp_buff; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.OutputLength != sizeof(struct bcm_host_stats_mibs)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Length Check failed %lu %zd\n", IoBuffer.OutputLength, + sizeof(struct bcm_host_stats_mibs)); + return -EINVAL; + } + + /* FIXME: HOST_STATS are too big for kmalloc (122048)! */ + temp_buff = kzalloc(sizeof(struct bcm_host_stats_mibs), GFP_KERNEL); + if (!temp_buff) + return STATUS_FAILURE; + + Status = ProcessGetHostMibs(Adapter, temp_buff); + GetDroppedAppCntrlPktMibs(temp_buff, pTarang); + + if (Status != STATUS_FAILURE) { + if (copy_to_user(IoBuffer.OutputBuffer, temp_buff, + sizeof(struct bcm_host_stats_mibs))) { + kfree(temp_buff); + return -EFAULT; + } + } + + kfree(temp_buff); + return Status; +} + +static int bcm_char_ioctl_bulk_wrm(void __user *argp, + struct bcm_mini_adapter *Adapter, UINT cmd) +{ + struct bcm_bulk_wrm_buffer *pBulkBuffer; + struct bcm_ioctl_buffer IoBuffer; + UINT uiTempVar = 0; + INT Status = STATUS_FAILURE; + PCHAR pvBuffer = NULL; + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, + "Device in Idle/Shutdown Mode, Blocking Wrms\n"); + return -EACCES; + } + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.InputLength < sizeof(ULONG) * 2) + return -EINVAL; + + pvBuffer = memdup_user(IoBuffer.InputBuffer, + IoBuffer.InputLength); + if (IS_ERR(pvBuffer)) + return PTR_ERR(pvBuffer); + + pBulkBuffer = (struct bcm_bulk_wrm_buffer *)pvBuffer; + + if (((ULONG)pBulkBuffer->Register & 0x0F000000) != 0x0F000000 || + ((ULONG)pBulkBuffer->Register & 0x3)) { + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, + "WRM Done On invalid Address : %x Access Denied.\n", + (int)pBulkBuffer->Register); + kfree(pvBuffer); + return -EINVAL; + } + + uiTempVar = pBulkBuffer->Register & EEPROM_REJECT_MASK; + if (!((Adapter->pstargetparams->m_u32Customize)&VSG_MODE) && + ((uiTempVar == EEPROM_REJECT_REG_1) || + (uiTempVar == EEPROM_REJECT_REG_2) || + (uiTempVar == EEPROM_REJECT_REG_3) || + (uiTempVar == EEPROM_REJECT_REG_4)) && + (cmd == IOCTL_BCM_REGISTER_WRITE)) { + + kfree(pvBuffer); + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, + "EEPROM Access Denied, not in VSG Mode\n"); + return -EFAULT; + } + + if (pBulkBuffer->SwapEndian == false) + Status = wrmWithLock(Adapter, (UINT)pBulkBuffer->Register, + (PCHAR)pBulkBuffer->Values, + IoBuffer.InputLength - 2*sizeof(ULONG)); + else + Status = wrmaltWithLock(Adapter, (UINT)pBulkBuffer->Register, + (PUINT)pBulkBuffer->Values, + IoBuffer.InputLength - 2*sizeof(ULONG)); + + if (Status != STATUS_SUCCESS) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "WRM Failed\n"); + + kfree(pvBuffer); + return Status; +} + +static int bcm_char_ioctl_get_nvm_size(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (Adapter->eNVMType == NVM_EEPROM || Adapter->eNVMType == NVM_FLASH) { + if (copy_to_user(IoBuffer.OutputBuffer, &Adapter->uiNVMDSDSize, + sizeof(UINT))) + return -EFAULT; + } + + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_cal_init(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + UINT uiSectorSize = 0; + INT Status = STATUS_FAILURE; + + if (Adapter->eNVMType == NVM_FLASH) { + if (copy_from_user(&IoBuffer, argp, + sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (copy_from_user(&uiSectorSize, IoBuffer.InputBuffer, + sizeof(UINT))) + return -EFAULT; + + if ((uiSectorSize < MIN_SECTOR_SIZE) || + (uiSectorSize > MAX_SECTOR_SIZE)) { + if (copy_to_user(IoBuffer.OutputBuffer, + &Adapter->uiSectorSize, sizeof(UINT))) + return -EFAULT; + } else { + if (IsFlash2x(Adapter)) { + if (copy_to_user(IoBuffer.OutputBuffer, + &Adapter->uiSectorSize, sizeof(UINT))) + return -EFAULT; + } else { + if ((TRUE == Adapter->bShutStatus) || + (TRUE == Adapter->IdleMode)) { + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_PRINTK, 0, 0, + "Device is in Idle/Shutdown Mode\n"); + return -EACCES; + } + + Adapter->uiSectorSize = uiSectorSize; + BcmUpdateSectorSize(Adapter, + Adapter->uiSectorSize); + } + } + Status = STATUS_SUCCESS; + } else { + Status = STATUS_FAILURE; + } + return Status; +} + +static int bcm_char_ioctl_set_debug(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ +#ifdef DEBUG + struct bcm_ioctl_buffer IoBuffer; + struct bcm_user_debug_state sUserDebugState; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "In SET_DEBUG ioctl\n"); + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (copy_from_user(&sUserDebugState, IoBuffer.InputBuffer, + sizeof(struct bcm_user_debug_state))) + return -EFAULT; + + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, + "IOCTL_BCM_SET_DEBUG: OnOff=%d Type = 0x%x ", + sUserDebugState.OnOff, sUserDebugState.Type); + /* sUserDebugState.Subtype <<= 1; */ + sUserDebugState.Subtype = 1 << sUserDebugState.Subtype; + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_PRINTK, 0, 0, + "actual Subtype=0x%x\n", sUserDebugState.Subtype); + + /* Update new 'DebugState' in the Adapter */ + Adapter->stDebugState.type |= sUserDebugState.Type; + /* Subtype: A bitmap of 32 bits for Subtype per Type. + * Valid indexes in 'subtype' array: 1,2,4,8 + * corresponding to valid Type values. Hence we can use the 'Type' field + * as the index value, ignoring the array entries 0,3,5,6,7 ! + */ + if (sUserDebugState.OnOff) + Adapter->stDebugState.subtype[sUserDebugState.Type] |= + sUserDebugState.Subtype; + else + Adapter->stDebugState.subtype[sUserDebugState.Type] &= + ~sUserDebugState.Subtype; + + BCM_SHOW_DEBUG_BITMAP(Adapter); +#endif + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_nvm_rw(void __user *argp, + struct bcm_mini_adapter *Adapter, UINT cmd) +{ + struct bcm_nvm_readwrite stNVMReadWrite; + struct timeval tv0, tv1; + struct bcm_ioctl_buffer IoBuffer; + PUCHAR pReadData = NULL; + INT Status = STATUS_FAILURE; + + memset(&tv0, 0, sizeof(struct timeval)); + memset(&tv1, 0, sizeof(struct timeval)); + if ((Adapter->eNVMType == NVM_FLASH) && + (Adapter->uiFlashLayoutMajorVersion == 0)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "The Flash Control Section is Corrupted. Hence Rejection on NVM Read/Write\n"); + return -EFAULT; + } + + if (IsFlash2x(Adapter)) { + if ((Adapter->eActiveDSD != DSD0) && + (Adapter->eActiveDSD != DSD1) && + (Adapter->eActiveDSD != DSD2)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "No DSD is active..hence NVM Command is blocked"); + return STATUS_FAILURE; + } + } + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (copy_from_user(&stNVMReadWrite, + (IOCTL_BCM_NVM_READ == cmd) ? + IoBuffer.OutputBuffer : IoBuffer.InputBuffer, + sizeof(struct bcm_nvm_readwrite))) + return -EFAULT; + + /* + * Deny the access if the offset crosses the cal area limit. + */ + if (stNVMReadWrite.uiNumBytes > Adapter->uiNVMDSDSize) + return STATUS_FAILURE; + + if (stNVMReadWrite.uiOffset > + Adapter->uiNVMDSDSize - stNVMReadWrite.uiNumBytes) + return STATUS_FAILURE; + + pReadData = memdup_user(stNVMReadWrite.pBuffer, + stNVMReadWrite.uiNumBytes); + if (IS_ERR(pReadData)) + return PTR_ERR(pReadData); + + do_gettimeofday(&tv0); + if (IOCTL_BCM_NVM_READ == cmd) { + int ret = bcm_handle_nvm_read_cmd(Adapter, pReadData, + &stNVMReadWrite); + if (ret != STATUS_SUCCESS) + return ret; + } else { + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadData); + return -EACCES; + } + + Adapter->bHeaderChangeAllowed = TRUE; + if (IsFlash2x(Adapter)) { + int ret = handle_flash2x_adapter(Adapter, + pReadData, + &stNVMReadWrite); + if (ret != STATUS_SUCCESS) + return ret; + } + + Status = BeceemNVMWrite(Adapter, (PUINT)pReadData, + stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes, + stNVMReadWrite.bVerify); + if (IsFlash2x(Adapter)) + BcmFlash2xWriteSig(Adapter, Adapter->eActiveDSD); + + Adapter->bHeaderChangeAllowed = false; + + up(&Adapter->NVMRdmWrmLock); + + if (Status != STATUS_SUCCESS) { + kfree(pReadData); + return Status; + } + } + + do_gettimeofday(&tv1); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + " timetaken by Write/read :%ld msec\n", + (tv1.tv_sec - tv0.tv_sec)*1000 + + (tv1.tv_usec - tv0.tv_usec)/1000); + + kfree(pReadData); + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_flash2x_section_read(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_flash2x_readwrite sFlash2xRead = {0}; + struct bcm_ioctl_buffer IoBuffer; + PUCHAR pReadBuff = NULL; + UINT NOB = 0; + UINT BuffSize = 0; + UINT ReadBytes = 0; + UINT ReadOffset = 0; + INT Status = STATUS_FAILURE; + void __user *OutPutBuff; + + if (IsFlash2x(Adapter) != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash Does not have 2.x map"); + return -EINVAL; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, "IOCTL_BCM_FLASH2X_SECTION_READ Called"); + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + /* Reading FLASH 2.x READ structure */ + if (copy_from_user(&sFlash2xRead, IoBuffer.InputBuffer, + sizeof(struct bcm_flash2x_readwrite))) + return -EFAULT; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.Section :%x", + sFlash2xRead.Section); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.offset :%x", + sFlash2xRead.offset); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.numOfBytes :%x", + sFlash2xRead.numOfBytes); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.bVerify :%x\n", + sFlash2xRead.bVerify); + + /* This was internal to driver for raw read. + * now it has ben exposed to user space app. + */ + if (validateFlash2xReadWrite(Adapter, &sFlash2xRead) == false) + return STATUS_FAILURE; + + NOB = sFlash2xRead.numOfBytes; + if (NOB > Adapter->uiSectorSize) + BuffSize = Adapter->uiSectorSize; + else + BuffSize = NOB; + + ReadOffset = sFlash2xRead.offset; + OutPutBuff = IoBuffer.OutputBuffer; + pReadBuff = (PCHAR)kzalloc(BuffSize , GFP_KERNEL); + + if (pReadBuff == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Memory allocation failed for Flash 2.x Read Structure"); + return -ENOMEM; + } + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadBuff); + return -EACCES; + } + + while (NOB) { + if (NOB > Adapter->uiSectorSize) + ReadBytes = Adapter->uiSectorSize; + else + ReadBytes = NOB; + + /* Reading the data from Flash 2.x */ + Status = BcmFlash2xBulkRead(Adapter, (PUINT)pReadBuff, + sFlash2xRead.Section, ReadOffset, ReadBytes); + if (Status) { + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Flash 2x read err with Status :%d", + Status); + break; + } + + BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, pReadBuff, ReadBytes); + + Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes); + if (Status) { + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Copy to use failed with status :%d", Status); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadBuff); + return -EFAULT; + } + NOB = NOB - ReadBytes; + if (NOB) { + ReadOffset = ReadOffset + ReadBytes; + OutPutBuff = OutPutBuff + ReadBytes; + } + } + + up(&Adapter->NVMRdmWrmLock); + kfree(pReadBuff); + return Status; +} + +static int bcm_char_ioctl_flash2x_section_write(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_flash2x_readwrite sFlash2xWrite = {0}; + struct bcm_ioctl_buffer IoBuffer; + PUCHAR pWriteBuff; + void __user *InputAddr; + UINT NOB = 0; + UINT BuffSize = 0; + UINT WriteOffset = 0; + UINT WriteBytes = 0; + INT Status = STATUS_FAILURE; + + if (IsFlash2x(Adapter) != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash Does not have 2.x map"); + return -EINVAL; + } + + /* First make this False so that we can enable the Sector + * Permission Check in BeceemFlashBulkWrite + */ + Adapter->bAllDSDWriteAllow = false; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_FLASH2X_SECTION_WRITE Called"); + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + /* Reading FLASH 2.x READ structure */ + if (copy_from_user(&sFlash2xWrite, IoBuffer.InputBuffer, + sizeof(struct bcm_flash2x_readwrite))) + return -EFAULT; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.Section :%x", sFlash2xWrite.Section); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.offset :%d", sFlash2xWrite.offset); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.numOfBytes :%x", sFlash2xWrite.numOfBytes); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\nsFlash2xRead.bVerify :%x\n", sFlash2xWrite.bVerify); + + if ((sFlash2xWrite.Section != VSA0) && (sFlash2xWrite.Section != VSA1) + && (sFlash2xWrite.Section != VSA2)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Only VSA write is allowed"); + return -EINVAL; + } + + if (validateFlash2xReadWrite(Adapter, &sFlash2xWrite) == false) + return STATUS_FAILURE; + + InputAddr = sFlash2xWrite.pDataBuff; + WriteOffset = sFlash2xWrite.offset; + NOB = sFlash2xWrite.numOfBytes; + + if (NOB > Adapter->uiSectorSize) + BuffSize = Adapter->uiSectorSize; + else + BuffSize = NOB; + + pWriteBuff = kmalloc(BuffSize, GFP_KERNEL); + + if (pWriteBuff == NULL) + return -ENOMEM; + + /* extracting the remainder of the given offset. */ + WriteBytes = Adapter->uiSectorSize; + if (WriteOffset % Adapter->uiSectorSize) { + WriteBytes = Adapter->uiSectorSize - + (WriteOffset % Adapter->uiSectorSize); + } + + if (NOB < WriteBytes) + WriteBytes = NOB; + + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + kfree(pWriteBuff); + return -EACCES; + } + + BcmFlash2xCorruptSig(Adapter, sFlash2xWrite.Section); + do { + Status = copy_from_user(pWriteBuff, InputAddr, WriteBytes); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy to user failed with status :%d", Status); + up(&Adapter->NVMRdmWrmLock); + kfree(pWriteBuff); + return -EFAULT; + } + BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, + OSAL_DBG, DBG_LVL_ALL, pWriteBuff, WriteBytes); + + /* Writing the data from Flash 2.x */ + Status = BcmFlash2xBulkWrite(Adapter, (PUINT)pWriteBuff, + sFlash2xWrite.Section, + WriteOffset, + WriteBytes, + sFlash2xWrite.bVerify); + + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash 2x read err with Status :%d", Status); + break; + } + + NOB = NOB - WriteBytes; + if (NOB) { + WriteOffset = WriteOffset + WriteBytes; + InputAddr = InputAddr + WriteBytes; + if (NOB > Adapter->uiSectorSize) + WriteBytes = Adapter->uiSectorSize; + else + WriteBytes = NOB; + } + } while (NOB > 0); + + BcmFlash2xWriteSig(Adapter, sFlash2xWrite.Section); + up(&Adapter->NVMRdmWrmLock); + kfree(pWriteBuff); + return Status; +} + +static int bcm_char_ioctl_flash2x_section_bitmap(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_flash2x_bitmap *psFlash2xBitMap; + struct bcm_ioctl_buffer IoBuffer; + +BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP Called"); + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.OutputLength != sizeof(struct bcm_flash2x_bitmap)) + return -EINVAL; + + psFlash2xBitMap = kzalloc(sizeof(struct bcm_flash2x_bitmap), + GFP_KERNEL); + + if (psFlash2xBitMap == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Memory is not available"); + return -ENOMEM; + } + + /* Reading the Flash Sectio Bit map */ + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + kfree(psFlash2xBitMap); + return -EACCES; + } + + BcmGetFlash2xSectionalBitMap(Adapter, psFlash2xBitMap); + up(&Adapter->NVMRdmWrmLock); + if (copy_to_user(IoBuffer.OutputBuffer, psFlash2xBitMap, + sizeof(struct bcm_flash2x_bitmap))) { + kfree(psFlash2xBitMap); + return -EFAULT; + } + + kfree(psFlash2xBitMap); + return STATUS_FAILURE; +} + +static int bcm_char_ioctl_set_active_section(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + enum bcm_flash2x_section_val eFlash2xSectionVal = 0; + INT Status = STATUS_FAILURE; + struct bcm_ioctl_buffer IoBuffer; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_SET_ACTIVE_SECTION Called"); + + if (IsFlash2x(Adapter) != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash Does not have 2.x map"); + return -EINVAL; + } + + Status = copy_from_user(&IoBuffer, argp, + sizeof(struct bcm_ioctl_buffer)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of IOCTL BUFFER failed"); + return -EFAULT; + } + + Status = copy_from_user(&eFlash2xSectionVal, + IoBuffer.InputBuffer, sizeof(INT)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of flash section val failed"); + return -EFAULT; + } + + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + return -EACCES; + } + + Status = BcmSetActiveSection(Adapter, eFlash2xSectionVal); + if (Status) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Failed to make it's priority Highest. Status %d", + Status); + + up(&Adapter->NVMRdmWrmLock); + + return Status; +} + +static int bcm_char_ioctl_copy_section(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_flash2x_copy_section sCopySectStrut = {0}; + struct bcm_ioctl_buffer IoBuffer; + INT Status = STATUS_SUCCESS; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_COPY_SECTION Called"); + + Adapter->bAllDSDWriteAllow = false; + if (IsFlash2x(Adapter) != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash Does not have 2.x map"); + return -EINVAL; + } + + Status = copy_from_user(&IoBuffer, argp, + sizeof(struct bcm_ioctl_buffer)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of IOCTL BUFFER failed Status :%d", + Status); + return -EFAULT; + } + + Status = copy_from_user(&sCopySectStrut, IoBuffer.InputBuffer, + sizeof(struct bcm_flash2x_copy_section)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of Copy_Section_Struct failed with Status :%d", + Status); + return -EFAULT; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Source SEction :%x", sCopySectStrut.SrcSection); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Destination SEction :%x", sCopySectStrut.DstSection); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "offset :%x", sCopySectStrut.offset); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "NOB :%x", sCopySectStrut.numOfBytes); + + if (IsSectionExistInFlash(Adapter, sCopySectStrut.SrcSection) == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Source Section<%x> does not exist in Flash ", + sCopySectStrut.SrcSection); + return -EINVAL; + } + + if (IsSectionExistInFlash(Adapter, sCopySectStrut.DstSection) == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Destinatio Section<%x> does not exist in Flash ", + sCopySectStrut.DstSection); + return -EINVAL; + } + + if (sCopySectStrut.SrcSection == sCopySectStrut.DstSection) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Source and Destination section should be different"); + return -EINVAL; + } + + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + up(&Adapter->NVMRdmWrmLock); + return -EACCES; + } + + if (sCopySectStrut.SrcSection == ISO_IMAGE1 || + sCopySectStrut.SrcSection == ISO_IMAGE2) { + if (IsNonCDLessDevice(Adapter)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Device is Non-CDLess hence won't have ISO !!"); + Status = -EINVAL; + } else if (sCopySectStrut.numOfBytes == 0) { + Status = BcmCopyISO(Adapter, sCopySectStrut); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Partial Copy of ISO section is not Allowed.."); + Status = STATUS_FAILURE; + } + up(&Adapter->NVMRdmWrmLock); + return Status; + } + + Status = BcmCopySection(Adapter, sCopySectStrut.SrcSection, + sCopySectStrut.DstSection, + sCopySectStrut.offset, + sCopySectStrut.numOfBytes); + up(&Adapter->NVMRdmWrmLock); + return Status; +} + +static int bcm_char_ioctl_get_flash_cs_info(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + INT Status = STATUS_SUCCESS; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + " IOCTL_BCM_GET_FLASH_CS_INFO Called"); + + Status = copy_from_user(&IoBuffer, argp, + sizeof(struct bcm_ioctl_buffer)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of IOCTL BUFFER failed"); + return -EFAULT; + } + + if (Adapter->eNVMType != NVM_FLASH) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Connected device does not have flash"); + return -EINVAL; + } + + if (IsFlash2x(Adapter) == TRUE) { + if (IoBuffer.OutputLength < sizeof(struct bcm_flash2x_cs_info)) + return -EINVAL; + + if (copy_to_user(IoBuffer.OutputBuffer, + Adapter->psFlash2xCSInfo, + sizeof(struct bcm_flash2x_cs_info))) + return -EFAULT; + } else { + if (IoBuffer.OutputLength < sizeof(struct bcm_flash_cs_info)) + return -EINVAL; + + if (copy_to_user(IoBuffer.OutputBuffer, Adapter->psFlashCSInfo, + sizeof(struct bcm_flash_cs_info))) + return -EFAULT; + } + return Status; +} + +static int bcm_char_ioctl_select_dsd(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_ioctl_buffer IoBuffer; + INT Status = STATUS_FAILURE; + UINT SectOfset = 0; + enum bcm_flash2x_section_val eFlash2xSectionVal; + + eFlash2xSectionVal = NO_SECTION_VAL; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_SELECT_DSD Called"); + + if (IsFlash2x(Adapter) != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash Does not have 2.x map"); + return -EINVAL; + } + + Status = copy_from_user(&IoBuffer, argp, + sizeof(struct bcm_ioctl_buffer)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of IOCTL BUFFER failed"); + return -EFAULT; + } + Status = copy_from_user(&eFlash2xSectionVal, IoBuffer.InputBuffer, + sizeof(INT)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy of flash section val failed"); + return -EFAULT; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Read Section :%d", eFlash2xSectionVal); + if ((eFlash2xSectionVal != DSD0) && + (eFlash2xSectionVal != DSD1) && + (eFlash2xSectionVal != DSD2)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Passed section<%x> is not DSD section", + eFlash2xSectionVal); + return STATUS_FAILURE; + } + + SectOfset = BcmGetSectionValStartOffset(Adapter, eFlash2xSectionVal); + if (SectOfset == INVALID_OFFSET) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Provided Section val <%d> does not exist in Flash 2.x", + eFlash2xSectionVal); + return -EINVAL; + } + + Adapter->bAllDSDWriteAllow = TRUE; + Adapter->ulFlashCalStart = SectOfset; + Adapter->eActiveDSD = eFlash2xSectionVal; + + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_nvm_raw_read(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_nvm_readwrite stNVMRead; + struct bcm_ioctl_buffer IoBuffer; + unsigned int NOB; + INT BuffSize; + INT ReadOffset = 0; + UINT ReadBytes = 0; + PUCHAR pReadBuff; + void __user *OutPutBuff; + INT Status = STATUS_FAILURE; + + if (Adapter->eNVMType != NVM_FLASH) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "NVM TYPE is not Flash"); + return -EINVAL; + } + + /* Copy Ioctl Buffer structure */ + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "copy_from_user 1 failed\n"); + return -EFAULT; + } + + if (copy_from_user(&stNVMRead, IoBuffer.OutputBuffer, + sizeof(struct bcm_nvm_readwrite))) + return -EFAULT; + + NOB = stNVMRead.uiNumBytes; + /* In Raw-Read max Buff size : 64MB */ + + if (NOB > DEFAULT_BUFF_SIZE) + BuffSize = DEFAULT_BUFF_SIZE; + else + BuffSize = NOB; + + ReadOffset = stNVMRead.uiOffset; + OutPutBuff = stNVMRead.pBuffer; + + pReadBuff = kzalloc(BuffSize , GFP_KERNEL); + if (pReadBuff == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Memory allocation failed for Flash 2.x Read Structure"); + return -ENOMEM; + } + down(&Adapter->NVMRdmWrmLock); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Device is in Idle/Shutdown Mode\n"); + kfree(pReadBuff); + up(&Adapter->NVMRdmWrmLock); + return -EACCES; + } + + Adapter->bFlashRawRead = TRUE; + + while (NOB) { + if (NOB > DEFAULT_BUFF_SIZE) + ReadBytes = DEFAULT_BUFF_SIZE; + else + ReadBytes = NOB; + + /* Reading the data from Flash 2.x */ + Status = BeceemNVMRead(Adapter, (PUINT)pReadBuff, + ReadOffset, ReadBytes); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Flash 2x read err with Status :%d", + Status); + break; + } + + BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, + DBG_LVL_ALL, pReadBuff, ReadBytes); + + Status = copy_to_user(OutPutBuff, pReadBuff, ReadBytes); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "Copy to use failed with status :%d", + Status); + up(&Adapter->NVMRdmWrmLock); + kfree(pReadBuff); + return -EFAULT; + } + NOB = NOB - ReadBytes; + if (NOB) { + ReadOffset = ReadOffset + ReadBytes; + OutPutBuff = OutPutBuff + ReadBytes; + } + } + Adapter->bFlashRawRead = false; + up(&Adapter->NVMRdmWrmLock); + kfree(pReadBuff); + return Status; +} + +static int bcm_char_ioctl_cntrlmsg_mask(void __user *argp, + struct bcm_mini_adapter *Adapter, struct bcm_tarang_data *pTarang) +{ + struct bcm_ioctl_buffer IoBuffer; + INT Status = STATUS_FAILURE; + ULONG RxCntrlMsgBitMask = 0; + + /* Copy Ioctl Buffer structure */ + Status = copy_from_user(&IoBuffer, argp, + sizeof(struct bcm_ioctl_buffer)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "copy of Ioctl buffer is failed from user space"); + return -EFAULT; + } + + if (IoBuffer.InputLength != sizeof(unsigned long)) + return -EINVAL; + + Status = copy_from_user(&RxCntrlMsgBitMask, IoBuffer.InputBuffer, + IoBuffer.InputLength); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "copy of control bit mask failed from user space"); + return -EFAULT; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "\n Got user defined cntrl msg bit mask :%lx", + RxCntrlMsgBitMask); + pTarang->RxCntrlMsgBitMask = RxCntrlMsgBitMask; + + return Status; +} + +static int bcm_char_ioctl_get_device_driver_info(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_driver_info DevInfo; + struct bcm_ioctl_buffer IoBuffer; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Called IOCTL_BCM_GET_DEVICE_DRIVER_INFO\n"); + + memset(&DevInfo, 0, sizeof(DevInfo)); + DevInfo.MaxRDMBufferSize = BUFFER_4K; + DevInfo.u32DSDStartOffset = EEPROM_CALPARAM_START; + DevInfo.u32RxAlignmentCorrection = 0; + DevInfo.u32NVMType = Adapter->eNVMType; + DevInfo.u32InterfaceType = BCM_USB; + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.OutputLength < sizeof(DevInfo)) + return -EINVAL; + + if (copy_to_user(IoBuffer.OutputBuffer, &DevInfo, sizeof(DevInfo))) + return -EFAULT; + + return STATUS_SUCCESS; +} + +static int bcm_char_ioctl_time_since_net_entry(void __user *argp, + struct bcm_mini_adapter *Adapter) +{ + struct bcm_time_elapsed stTimeElapsedSinceNetEntry = {0}; + struct bcm_ioctl_buffer IoBuffer; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_TIME_SINCE_NET_ENTRY called"); + + if (copy_from_user(&IoBuffer, argp, sizeof(struct bcm_ioctl_buffer))) + return -EFAULT; + + if (IoBuffer.OutputLength < sizeof(struct bcm_time_elapsed)) + return -EINVAL; + + stTimeElapsedSinceNetEntry.ul64TimeElapsedSinceNetEntry = + get_seconds() - Adapter->liTimeSinceLastNetEntry; + + if (copy_to_user(IoBuffer.OutputBuffer, &stTimeElapsedSinceNetEntry, + sizeof(struct bcm_time_elapsed))) + return -EFAULT; + + return STATUS_SUCCESS; +} + + +static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg) +{ + struct bcm_tarang_data *pTarang = filp->private_data; + void __user *argp = (void __user *)arg; + struct bcm_mini_adapter *Adapter = pTarang->Adapter; + INT Status = STATUS_FAILURE; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "Parameters Passed to control IOCTL cmd=0x%X arg=0x%lX", + cmd, arg); + + if (_IOC_TYPE(cmd) != BCM_IOCTL) + return -EFAULT; + if (_IOC_DIR(cmd) & _IOC_READ) + Status = !access_ok(VERIFY_WRITE, argp, _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + Status = !access_ok(VERIFY_READ, argp, _IOC_SIZE(cmd)); + else if (_IOC_NONE == (_IOC_DIR(cmd) & _IOC_NONE)) + Status = STATUS_SUCCESS; + + if (Status) + return -EFAULT; + + if (Adapter->device_removed) + return -EFAULT; + + if (false == Adapter->fw_download_done) { + switch (cmd) { + case IOCTL_MAC_ADDR_REQ: + case IOCTL_LINK_REQ: + case IOCTL_CM_REQUEST: + case IOCTL_SS_INFO_REQ: + case IOCTL_SEND_CONTROL_MESSAGE: + case IOCTL_IDLE_REQ: + case IOCTL_BCM_GPIO_SET_REQUEST: + case IOCTL_BCM_GPIO_STATUS_REQUEST: + return -EACCES; + default: + break; + } + } + + Status = vendorextnIoctl(Adapter, cmd, arg); + if (Status != CONTINUE_COMMON_PATH) + return Status; + + switch (cmd) { + /* Rdms for Swin Idle... */ + case IOCTL_BCM_REGISTER_READ_PRIVATE: + Status = bcm_char_ioctl_reg_read_private(argp, Adapter); + return Status; + + case IOCTL_BCM_REGISTER_WRITE_PRIVATE: + Status = bcm_char_ioctl_reg_write_private(argp, Adapter); + return Status; + + case IOCTL_BCM_REGISTER_READ: + case IOCTL_BCM_EEPROM_REGISTER_READ: + Status = bcm_char_ioctl_eeprom_reg_read(argp, Adapter); + return Status; + + case IOCTL_BCM_REGISTER_WRITE: + case IOCTL_BCM_EEPROM_REGISTER_WRITE: + Status = bcm_char_ioctl_eeprom_reg_write(argp, Adapter, cmd); + return Status; + + case IOCTL_BCM_GPIO_SET_REQUEST: + Status = bcm_char_ioctl_gpio_set_request(argp, Adapter); + return Status; + + case BCM_LED_THREAD_STATE_CHANGE_REQ: + Status = bcm_char_ioctl_led_thread_state_change_req(argp, + Adapter); + return Status; + + case IOCTL_BCM_GPIO_STATUS_REQUEST: + Status = bcm_char_ioctl_gpio_status_request(argp, Adapter); + return Status; + + case IOCTL_BCM_GPIO_MULTI_REQUEST: + Status = bcm_char_ioctl_gpio_multi_request(argp, Adapter); + return Status; + + case IOCTL_BCM_GPIO_MODE_REQUEST: + Status = bcm_char_ioctl_gpio_mode_request(argp, Adapter); + return Status; + + case IOCTL_MAC_ADDR_REQ: + case IOCTL_LINK_REQ: + case IOCTL_CM_REQUEST: + case IOCTL_SS_INFO_REQ: + case IOCTL_SEND_CONTROL_MESSAGE: + case IOCTL_IDLE_REQ: + Status = bcm_char_ioctl_misc_request(argp, Adapter); + return Status; + + case IOCTL_BCM_BUFFER_DOWNLOAD_START: + Status = bcm_char_ioctl_buffer_download_start(Adapter); + return Status; + + case IOCTL_BCM_BUFFER_DOWNLOAD: + Status = bcm_char_ioctl_buffer_download(argp, Adapter); + return Status; + + case IOCTL_BCM_BUFFER_DOWNLOAD_STOP: + Status = bcm_char_ioctl_buffer_download_stop(argp, Adapter); + return Status; + + + case IOCTL_BE_BUCKET_SIZE: + Status = 0; + if (get_user(Adapter->BEBucketSize, + (unsigned long __user *)arg)) + Status = -EFAULT; + break; + + case IOCTL_RTPS_BUCKET_SIZE: + Status = 0; + if (get_user(Adapter->rtPSBucketSize, + (unsigned long __user *)arg)) + Status = -EFAULT; + break; + + case IOCTL_CHIP_RESET: + Status = bcm_char_ioctl_chip_reset(Adapter); + return Status; + + case IOCTL_QOS_THRESHOLD: + Status = bcm_char_ioctl_qos_threshold(arg, Adapter); + return Status; + + case IOCTL_DUMP_PACKET_INFO: + DumpPackInfo(Adapter); + DumpPhsRules(&Adapter->stBCMPhsContext); + Status = STATUS_SUCCESS; + break; + + case IOCTL_GET_PACK_INFO: + if (copy_to_user(argp, &Adapter->PackInfo, + sizeof(struct bcm_packet_info)*NO_OF_QUEUES)) + return -EFAULT; + Status = STATUS_SUCCESS; + break; + + case IOCTL_BCM_SWITCH_TRANSFER_MODE: + Status = bcm_char_ioctl_switch_transfer_mode(argp, Adapter); + return Status; + + case IOCTL_BCM_GET_DRIVER_VERSION: + Status = bcm_char_ioctl_get_driver_version(argp); + return Status; + + case IOCTL_BCM_GET_CURRENT_STATUS: + Status = bcm_char_ioctl_get_current_status(argp, Adapter); + return Status; + + case IOCTL_BCM_SET_MAC_TRACING: + Status = bcm_char_ioctl_set_mac_tracing(argp, Adapter); + return Status; + + case IOCTL_BCM_GET_DSX_INDICATION: + Status = bcm_char_ioctl_get_dsx_indication(argp, Adapter); + return Status; + + case IOCTL_BCM_GET_HOST_MIBS: + Status = bcm_char_ioctl_get_host_mibs(argp, Adapter, pTarang); + return Status; + + case IOCTL_BCM_WAKE_UP_DEVICE_FROM_IDLE: + if ((false == Adapter->bTriedToWakeUpFromlowPowerMode) && + (TRUE == Adapter->IdleMode)) { + Adapter->usIdleModePattern = ABORT_IDLE_MODE; + Adapter->bWakeUpDevice = TRUE; + wake_up(&Adapter->process_rx_cntrlpkt); + } + + Status = STATUS_SUCCESS; + break; + + case IOCTL_BCM_BULK_WRM: + Status = bcm_char_ioctl_bulk_wrm(argp, Adapter, cmd); + return Status; + + case IOCTL_BCM_GET_NVM_SIZE: + Status = bcm_char_ioctl_get_nvm_size(argp, Adapter); + return Status; + + case IOCTL_BCM_CAL_INIT: + Status = bcm_char_ioctl_cal_init(argp, Adapter); + return Status; + + case IOCTL_BCM_SET_DEBUG: + Status = bcm_char_ioctl_set_debug(argp, Adapter); + return Status; + + case IOCTL_BCM_NVM_READ: + case IOCTL_BCM_NVM_WRITE: + Status = bcm_char_ioctl_nvm_rw(argp, Adapter, cmd); + return Status; + + case IOCTL_BCM_FLASH2X_SECTION_READ: + Status = bcm_char_ioctl_flash2x_section_read(argp, Adapter); + return Status; + + case IOCTL_BCM_FLASH2X_SECTION_WRITE: + Status = bcm_char_ioctl_flash2x_section_write(argp, Adapter); + return Status; + + case IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP: + Status = bcm_char_ioctl_flash2x_section_bitmap(argp, Adapter); + return Status; + + case IOCTL_BCM_SET_ACTIVE_SECTION: + Status = bcm_char_ioctl_set_active_section(argp, Adapter); + return Status; + + case IOCTL_BCM_IDENTIFY_ACTIVE_SECTION: + /* Right Now we are taking care of only DSD */ + Adapter->bAllDSDWriteAllow = false; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_BCM_IDENTIFY_ACTIVE_SECTION called"); + Status = STATUS_SUCCESS; + break; + + case IOCTL_BCM_COPY_SECTION: + Status = bcm_char_ioctl_copy_section(argp, Adapter); + return Status; + + case IOCTL_BCM_GET_FLASH_CS_INFO: + Status = bcm_char_ioctl_get_flash_cs_info(argp, Adapter); + return Status; + + case IOCTL_BCM_SELECT_DSD: + Status = bcm_char_ioctl_select_dsd(argp, Adapter); + return Status; + + case IOCTL_BCM_NVM_RAW_READ: + Status = bcm_char_ioctl_nvm_raw_read(argp, Adapter); + return Status; + + case IOCTL_BCM_CNTRLMSG_MASK: + Status = bcm_char_ioctl_cntrlmsg_mask(argp, Adapter, pTarang); + return Status; + + case IOCTL_BCM_GET_DEVICE_DRIVER_INFO: + Status = bcm_char_ioctl_get_device_driver_info(argp, Adapter); + return Status; + + case IOCTL_BCM_TIME_SINCE_NET_ENTRY: + Status = bcm_char_ioctl_time_since_net_entry(argp, Adapter); + return Status; + + case IOCTL_CLOSE_NOTIFICATION: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, OSAL_DBG, DBG_LVL_ALL, + "IOCTL_CLOSE_NOTIFICATION"); + break; + + default: + pr_info(DRV_NAME ": unknown ioctl cmd=%#x\n", cmd); + Status = STATUS_FAILURE; + break; + } + return Status; +} + + +static const struct file_operations bcm_fops = { + .owner = THIS_MODULE, + .open = bcm_char_open, + .release = bcm_char_release, + .read = bcm_char_read, + .unlocked_ioctl = bcm_char_ioctl, + .llseek = no_llseek, +}; + +int register_control_device_interface(struct bcm_mini_adapter *Adapter) +{ + + if (Adapter->major > 0) + return Adapter->major; + + Adapter->major = register_chrdev(0, DEV_NAME, &bcm_fops); + if (Adapter->major < 0) { + pr_err(DRV_NAME ": could not created character device\n"); + return Adapter->major; + } + + Adapter->pstCreatedClassDevice = device_create(bcm_class, NULL, + MKDEV(Adapter->major, 0), + Adapter, DEV_NAME); + + if (IS_ERR(Adapter->pstCreatedClassDevice)) { + pr_err(DRV_NAME ": class device create failed\n"); + unregister_chrdev(Adapter->major, DEV_NAME); + return PTR_ERR(Adapter->pstCreatedClassDevice); + } + + return 0; +} + +void unregister_control_device_interface(struct bcm_mini_adapter *Adapter) +{ + if (Adapter->major > 0) { + device_destroy(bcm_class, MKDEV(Adapter->major, 0)); + unregister_chrdev(Adapter->major, DEV_NAME); + } +} + diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c new file mode 100644 index 00000000000..95a2358267b --- /dev/null +++ b/drivers/staging/bcm/Bcmnet.c @@ -0,0 +1,241 @@ +#include "headers.h" + +struct net_device *gblpnetdev; + +static INT bcm_open(struct net_device *dev) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + + if (Adapter->fw_download_done == false) { + pr_notice(PFX "%s: link up failed (download in progress)\n", + dev->name); + return -EBUSY; + } + + if (netif_msg_ifup(Adapter)) + pr_info(PFX "%s: enabling interface\n", dev->name); + + if (Adapter->LinkUpStatus) { + if (netif_msg_link(Adapter)) + pr_info(PFX "%s: link up\n", dev->name); + + netif_carrier_on(Adapter->dev); + netif_start_queue(Adapter->dev); + } + + return 0; +} + +static INT bcm_close(struct net_device *dev) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + + if (netif_msg_ifdown(Adapter)) + pr_info(PFX "%s: disabling interface\n", dev->name); + + netif_carrier_off(dev); + netif_stop_queue(dev); + + return 0; +} + +static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv, select_queue_fallback_t fallback) +{ + return ClassifyPacket(netdev_priv(dev), skb); +} + +/******************************************************************* +* Function - bcm_transmit() +* +* Description - This is the main transmit function for our virtual +* interface(eth0). It handles the ARP packets. It +* clones this packet and then Queue it to a suitable +* Queue. Then calls the transmit_packet(). +* +* Parameter - skb - Pointer to the socket buffer structure +* dev - Pointer to the virtual net device structure +* +*********************************************************************/ + +static netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + u16 qindex = skb_get_queue_mapping(skb); + + + if (Adapter->device_removed || !Adapter->LinkUpStatus) + goto drop; + + if (Adapter->TransferMode != IP_PACKET_ONLY_MODE) + goto drop; + + if (INVALID_QUEUE_INDEX == qindex) + goto drop; + + if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= + SF_MAX_ALLOWED_PACKETS_TO_BACKUP) + return NETDEV_TX_BUSY; + + /* Now Enqueue the packet */ + if (netif_msg_tx_queued(Adapter)) + pr_info(PFX "%s: enqueueing packet to queue %d\n", + dev->name, qindex); + + spin_lock(&Adapter->PackInfo[qindex].SFQueueLock); + Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len; + Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++; + + *((B_UINT32 *) skb->cb + SKB_CB_LATENCY_OFFSET) = jiffies; + ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue, + Adapter->PackInfo[qindex].LastTxQueue, skb); + atomic_inc(&Adapter->TotalPacketCount); + spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock); + + /* FIXME - this is racy and incorrect, replace with work queue */ + if (!atomic_read(&Adapter->TxPktAvail)) { + atomic_set(&Adapter->TxPktAvail, 1); + wake_up(&Adapter->tx_packet_wait_queue); + } + return NETDEV_TX_OK; + + drop: + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + + + +/** +@ingroup init_functions +Register other driver entry points with the kernel +*/ +static const struct net_device_ops bcmNetDevOps = { + .ndo_open = bcm_open, + .ndo_stop = bcm_close, + .ndo_start_xmit = bcm_transmit, + .ndo_change_mtu = eth_change_mtu, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_select_queue = bcm_select_queue, +}; + +static struct device_type wimax_type = { + .name = "wimax", +}; + +static int bcm_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + cmd->supported = 0; + cmd->advertising = 0; + cmd->speed = SPEED_10000; + cmd->duplex = DUPLEX_FULL; + cmd->port = PORT_TP; + cmd->phy_address = 0; + cmd->transceiver = XCVR_INTERNAL; + cmd->autoneg = AUTONEG_DISABLE; + cmd->maxtxpkt = 0; + cmd->maxrxpkt = 0; + return 0; +} + +static void bcm_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + struct bcm_interface_adapter *psIntfAdapter = + Adapter->pvInterfaceAdapter; + struct usb_device *udev = interface_to_usbdev(psIntfAdapter->interface); + + strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); + strlcpy(info->version, DRV_VERSION, sizeof(info->version)); + snprintf(info->fw_version, sizeof(info->fw_version), "%u.%u", + Adapter->uiFlashLayoutMajorVersion, + Adapter->uiFlashLayoutMinorVersion); + + usb_make_path(udev, info->bus_info, sizeof(info->bus_info)); +} + +static u32 bcm_get_link(struct net_device *dev) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + + return Adapter->LinkUpStatus; +} + +static u32 bcm_get_msglevel(struct net_device *dev) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + + return Adapter->msg_enable; +} + +static void bcm_set_msglevel(struct net_device *dev, u32 level) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); + + Adapter->msg_enable = level; +} + +static const struct ethtool_ops bcm_ethtool_ops = { + .get_settings = bcm_get_settings, + .get_drvinfo = bcm_get_drvinfo, + .get_link = bcm_get_link, + .get_msglevel = bcm_get_msglevel, + .set_msglevel = bcm_set_msglevel, +}; + +int register_networkdev(struct bcm_mini_adapter *Adapter) +{ + struct net_device *net = Adapter->dev; + struct bcm_interface_adapter *IntfAdapter = Adapter->pvInterfaceAdapter; + struct usb_interface *udev = IntfAdapter->interface; + struct usb_device *xdev = IntfAdapter->udev; + + int result; + + net->netdev_ops = &bcmNetDevOps; + net->ethtool_ops = &bcm_ethtool_ops; + net->mtu = MTU_SIZE; /* 1400 Bytes */ + net->tx_queue_len = TX_QLEN; + net->flags |= IFF_NOARP; + + netif_carrier_off(net); + + SET_NETDEV_DEVTYPE(net, &wimax_type); + + /* Read the MAC Address from EEPROM */ + result = ReadMacAddressFromNVM(Adapter); + if (result != STATUS_SUCCESS) { + dev_err(&udev->dev, + PFX "Error in Reading the mac Address: %d", result); + return -EIO; + } + + result = register_netdev(net); + if (result) + return result; + + gblpnetdev = Adapter->dev; + + if (netif_msg_probe(Adapter)) + dev_info(&udev->dev, PFX "%s: register usb-%s-%s %pM\n", + net->name, xdev->bus->bus_name, xdev->devpath, + net->dev_addr); + + return 0; +} + +void unregister_networkdev(struct bcm_mini_adapter *Adapter) +{ + struct net_device *net = Adapter->dev; + struct bcm_interface_adapter *IntfAdapter = Adapter->pvInterfaceAdapter; + struct usb_interface *udev = IntfAdapter->interface; + struct usb_device *xdev = IntfAdapter->udev; + + if (netif_msg_probe(Adapter)) + dev_info(&udev->dev, PFX "%s: unregister usb-%s%s\n", + net->name, xdev->bus->bus_name, xdev->devpath); + + unregister_netdev(Adapter->dev); +} diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c new file mode 100644 index 00000000000..fb1d932c5d7 --- /dev/null +++ b/drivers/staging/bcm/CmHost.c @@ -0,0 +1,2253 @@ +/************************************************************ + * CMHOST.C + * This file contains the routines for handling Connection + * Management. + ************************************************************/ + +#include "headers.h" + +enum E_CLASSIFIER_ACTION { + eInvalidClassifierAction, + eAddClassifier, + eReplaceClassifier, + eDeleteClassifier +}; + +static ULONG GetNextTargetBufferLocation(struct bcm_mini_adapter *Adapter, + B_UINT16 tid); +static void restore_endianess_of_pstClassifierEntry( + struct bcm_classifier_rule *pstClassifierEntry, + enum bcm_ipaddr_context eIpAddrContext); + +static void apply_phs_rule_to_all_classifiers( + register struct bcm_mini_adapter *Adapter, + register UINT uiSearchRuleIndex, + USHORT uVCID, + struct bcm_phs_rule *sPhsRule, + struct bcm_phs_rules *cPhsRule, + struct bcm_add_indication_alt *pstAddIndication); + +/************************************************************ + * Function - SearchSfid + * + * Description - This routinue would search QOS queues having + * specified SFID as input parameter. + * + * Parameters - Adapter: Pointer to the Adapter structure + * uiSfid : Given SFID for matching + * + * Returns - Queue index for this SFID(If matched) + * Else Invalid Queue Index(If Not matched) + ************************************************************/ +int SearchSfid(struct bcm_mini_adapter *Adapter, UINT uiSfid) +{ + int i; + + for (i = (NO_OF_QUEUES-1); i >= 0; i--) + if (Adapter->PackInfo[i].ulSFID == uiSfid) + return i; + + return NO_OF_QUEUES+1; +} + +/*************************************************************** + * Function -SearchFreeSfid + * + * Description - This routinue would search Free available SFID. + * + * Parameter - Adapter: Pointer to the Adapter structure + * + * Returns - Queue index for the free SFID + * Else returns Invalid Index. + ****************************************************************/ +static int SearchFreeSfid(struct bcm_mini_adapter *Adapter) +{ + int i; + + for (i = 0; i < (NO_OF_QUEUES-1); i++) + if (Adapter->PackInfo[i].ulSFID == 0) + return i; + + return NO_OF_QUEUES+1; +} + +/* + * Function: SearchClsid + * Description: This routinue would search Classifier having specified ClassifierID as input parameter + * Input parameters: struct bcm_mini_adapter *Adapter - Adapter Context + * unsigned int uiSfid - The SF in which the classifier is to searched + * B_UINT16 uiClassifierID - The classifier ID to be searched + * Return: int :Classifier table index of matching entry + */ +static int SearchClsid(struct bcm_mini_adapter *Adapter, + ULONG ulSFID, + B_UINT16 uiClassifierID) +{ + int i; + + for (i = 0; i < MAX_CLASSIFIERS; i++) { + if ((Adapter->astClassifierTable[i].bUsed) && + (Adapter->astClassifierTable[i].uiClassifierRuleIndex + == uiClassifierID) && + (Adapter->astClassifierTable[i].ulSFID == ulSFID)) + return i; + } + + return MAX_CLASSIFIERS+1; +} + +/* + * @ingroup ctrl_pkt_functions + * This routinue would search Free available Classifier entry in classifier table. + * @return free Classifier Entry index in classifier table for specified SF + */ +static int SearchFreeClsid(struct bcm_mini_adapter *Adapter /**Adapter Context*/) +{ + int i; + + for (i = 0; i < MAX_CLASSIFIERS; i++) { + if (!Adapter->astClassifierTable[i].bUsed) + return i; + } + + return MAX_CLASSIFIERS+1; +} + +static VOID deleteSFBySfid(struct bcm_mini_adapter *Adapter, + UINT uiSearchRuleIndex) +{ + /* deleting all the packet held in the SF */ + flush_queue(Adapter, uiSearchRuleIndex); + + /* Deleting the all classifiers for this SF */ + DeleteAllClassifiersForSF(Adapter, uiSearchRuleIndex); + + /* Resetting only MIBS related entries in the SF */ + memset((PVOID)&Adapter->PackInfo[uiSearchRuleIndex], 0, + sizeof(struct bcm_mibs_table)); +} + +static inline VOID +CopyIpAddrToClassifier(struct bcm_classifier_rule *pstClassifierEntry, + B_UINT8 u8IpAddressLen, B_UINT8 *pu8IpAddressMaskSrc, + bool bIpVersion6, enum bcm_ipaddr_context eIpAddrContext) +{ + int i = 0; + UINT nSizeOfIPAddressInBytes = IP_LENGTH_OF_ADDRESS; + UCHAR *ptrClassifierIpAddress = NULL; + UCHAR *ptrClassifierIpMask = NULL; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + if (bIpVersion6) + nSizeOfIPAddressInBytes = IPV6_ADDRESS_SIZEINBYTES; + + /* Destination Ip Address */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Ip Address Range Length:0x%X ", u8IpAddressLen); + if ((bIpVersion6 ? (IPV6_ADDRESS_SIZEINBYTES * MAX_IP_RANGE_LENGTH * 2) : + (TOTAL_MASKED_ADDRESS_IN_BYTES)) >= u8IpAddressLen) { + + union u_ip_address *st_dest_ip = + &pstClassifierEntry->stDestIpAddress; + + union u_ip_address *st_src_ip = + &pstClassifierEntry->stSrcIpAddress; + + /* + * checking both the mask and address togethor in Classification. + * So length will be : TotalLengthInBytes/nSizeOfIPAddressInBytes * 2 + * (nSizeOfIPAddressInBytes for address and nSizeOfIPAddressInBytes for mask) + */ + if (eIpAddrContext == eDestIpAddress) { + pstClassifierEntry->ucIPDestinationAddressLength = + u8IpAddressLen/(nSizeOfIPAddressInBytes * 2); + if (bIpVersion6) { + ptrClassifierIpAddress = + st_dest_ip->ucIpv6Address; + ptrClassifierIpMask = + st_dest_ip->ucIpv6Mask; + } else { + ptrClassifierIpAddress = + st_dest_ip->ucIpv4Address; + ptrClassifierIpMask = + st_dest_ip->ucIpv4Mask; + } + } else if (eIpAddrContext == eSrcIpAddress) { + pstClassifierEntry->ucIPSourceAddressLength = + u8IpAddressLen/(nSizeOfIPAddressInBytes * 2); + if (bIpVersion6) { + ptrClassifierIpAddress = + st_src_ip->ucIpv6Address; + ptrClassifierIpMask = st_src_ip->ucIpv6Mask; + } else { + ptrClassifierIpAddress = + st_src_ip->ucIpv4Address; + ptrClassifierIpMask = st_src_ip->ucIpv4Mask; + } + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Address Length:0x%X\n", + pstClassifierEntry->ucIPDestinationAddressLength); + while ((u8IpAddressLen >= nSizeOfIPAddressInBytes) + && (i < MAX_IP_RANGE_LENGTH)) { + memcpy(ptrClassifierIpAddress + + (i * nSizeOfIPAddressInBytes), + (pu8IpAddressMaskSrc + + (i * nSizeOfIPAddressInBytes * 2)), + nSizeOfIPAddressInBytes); + + if (!bIpVersion6) { + if (eIpAddrContext == eSrcIpAddress) { + st_src_ip->ulIpv4Addr[i] = + ntohl(st_src_ip->ulIpv4Addr[i]); + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, + CONN_MSG, + DBG_LVL_ALL, + "Src Ip Address:0x%luX ", + st_src_ip->ulIpv4Addr[i]); + } else if (eIpAddrContext == eDestIpAddress) { + st_dest_ip->ulIpv4Addr[i] = + ntohl(st_dest_ip->ulIpv4Addr[i]); + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, + CONN_MSG, + DBG_LVL_ALL, + "Dest Ip Address:0x%luX ", + st_dest_ip->ulIpv4Addr[i]); + } + } + u8IpAddressLen -= nSizeOfIPAddressInBytes; + if (u8IpAddressLen >= nSizeOfIPAddressInBytes) { + memcpy(ptrClassifierIpMask + + (i * nSizeOfIPAddressInBytes), + (pu8IpAddressMaskSrc + + nSizeOfIPAddressInBytes + + (i * nSizeOfIPAddressInBytes * 2)), + nSizeOfIPAddressInBytes); + + if (!bIpVersion6) { + if (eIpAddrContext == eSrcIpAddress) { + st_src_ip->ulIpv4Mask[i] = + ntohl(st_src_ip->ulIpv4Mask[i]); + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, + CONN_MSG, + DBG_LVL_ALL, + "Src Ip Mask Address:0x%luX ", + st_src_ip->ulIpv4Mask[i]); + } else if (eIpAddrContext == eDestIpAddress) { + st_dest_ip->ulIpv4Mask[i] = + ntohl(st_dest_ip->ulIpv4Mask[i]); + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, + CONN_MSG, + DBG_LVL_ALL, + "Dest Ip Mask Address:0x%luX ", + st_dest_ip->ulIpv4Mask[i]); + } + } + u8IpAddressLen -= nSizeOfIPAddressInBytes; + } + if (u8IpAddressLen == 0) + pstClassifierEntry->bDestIpValid = TRUE; + + i++; + } + if (bIpVersion6) { + /* Restore EndianNess of Struct */ + restore_endianess_of_pstClassifierEntry( + pstClassifierEntry, + eIpAddrContext + ); + } + } +} + +void ClearTargetDSXBuffer(struct bcm_mini_adapter *Adapter, B_UINT16 TID, bool bFreeAll) +{ + int i; + struct bcm_targetdsx_buffer *curr_buf; + + for (i = 0; i < Adapter->ulTotalTargetBuffersAvailable; i++) { + curr_buf = &Adapter->astTargetDsxBuffer[i]; + + if (curr_buf->valid) + continue; + + if ((bFreeAll) || (curr_buf->tid == TID)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "ClearTargetDSXBuffer: found tid %d buffer cleared %lx\n", + TID, curr_buf->ulTargetDsxBuffer); + curr_buf->valid = 1; + curr_buf->tid = 0; + Adapter->ulFreeTargetBufferCnt++; + } + } +} + +/* + * @ingroup ctrl_pkt_functions + * copy classifier rule into the specified SF index + */ +static inline VOID CopyClassifierRuleToSF(struct bcm_mini_adapter *Adapter, + struct bcm_convergence_types *psfCSType, + UINT uiSearchRuleIndex, + UINT nClassifierIndex) +{ + struct bcm_classifier_rule *pstClassifierEntry = NULL; + /* VOID *pvPhsContext = NULL; */ + int i; + /* UCHAR ucProtocolLength=0; */ + /* ULONG ulPhsStatus; */ + + struct bcm_packet_class_rules *pack_class_rule = + &psfCSType->cCPacketClassificationRule; + + if (Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value == 0 || + nClassifierIndex > (MAX_CLASSIFIERS-1)) + return; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Storing Classifier Rule Index : %X", + ntohs(pack_class_rule->u16PacketClassificationRuleIndex)); + + if (nClassifierIndex > MAX_CLASSIFIERS-1) + return; + + pstClassifierEntry = &Adapter->astClassifierTable[nClassifierIndex]; + if (pstClassifierEntry) { + /* Store if Ipv6 */ + pstClassifierEntry->bIpv6Protocol = + (Adapter->PackInfo[uiSearchRuleIndex].ucIpVersion == IPV6) ? TRUE : false; + + /* Destinaiton Port */ + pstClassifierEntry->ucDestPortRangeLength = + pack_class_rule->u8ProtocolDestPortRangeLength / 4; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Destination Port Range Length:0x%X ", + pstClassifierEntry->ucDestPortRangeLength); + + if (pack_class_rule->u8ProtocolDestPortRangeLength <= MAX_PORT_RANGE) { + for (i = 0; i < (pstClassifierEntry->ucDestPortRangeLength); i++) { + pstClassifierEntry->usDestPortRangeLo[i] = + *((PUSHORT)(pack_class_rule->u8ProtocolDestPortRange+i)); + pstClassifierEntry->usDestPortRangeHi[i] = + *((PUSHORT)(pack_class_rule->u8ProtocolDestPortRange+2+i)); + pstClassifierEntry->usDestPortRangeLo[i] = + ntohs(pstClassifierEntry->usDestPortRangeLo[i]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + CONN_MSG, DBG_LVL_ALL, + "Destination Port Range Lo:0x%X ", + pstClassifierEntry->usDestPortRangeLo[i]); + pstClassifierEntry->usDestPortRangeHi[i] = + ntohs(pstClassifierEntry->usDestPortRangeHi[i]); + } + } else { + pstClassifierEntry->ucDestPortRangeLength = 0; + } + + /* Source Port */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Source Port Range Length:0x%X ", + pack_class_rule->u8ProtocolSourcePortRangeLength); + if (pack_class_rule->u8ProtocolSourcePortRangeLength <= MAX_PORT_RANGE) { + pstClassifierEntry->ucSrcPortRangeLength = + pack_class_rule->u8ProtocolSourcePortRangeLength/4; + for (i = 0; i < (pstClassifierEntry->ucSrcPortRangeLength); i++) { + pstClassifierEntry->usSrcPortRangeLo[i] = + *((PUSHORT)(pack_class_rule-> + u8ProtocolSourcePortRange+i)); + pstClassifierEntry->usSrcPortRangeHi[i] = + *((PUSHORT)(pack_class_rule-> + u8ProtocolSourcePortRange+2+i)); + pstClassifierEntry->usSrcPortRangeLo[i] = + ntohs(pstClassifierEntry->usSrcPortRangeLo[i]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + CONN_MSG, DBG_LVL_ALL, + "Source Port Range Lo:0x%X ", + pstClassifierEntry->usSrcPortRangeLo[i]); + pstClassifierEntry->usSrcPortRangeHi[i] = + ntohs(pstClassifierEntry->usSrcPortRangeHi[i]); + } + } + /* Destination Ip Address and Mask */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Ip Destination Parameters : "); + CopyIpAddrToClassifier(pstClassifierEntry, + pack_class_rule->u8IPDestinationAddressLength, + pack_class_rule->u8IPDestinationAddress, + (Adapter->PackInfo[uiSearchRuleIndex].ucIpVersion == IPV6) ? + TRUE : false, eDestIpAddress); + + /* Source Ip Address and Mask */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Ip Source Parameters : "); + + CopyIpAddrToClassifier(pstClassifierEntry, + pack_class_rule->u8IPMaskedSourceAddressLength, + pack_class_rule->u8IPMaskedSourceAddress, + (Adapter->PackInfo[uiSearchRuleIndex].ucIpVersion == IPV6) ? TRUE : false, + eSrcIpAddress); + + /* TOS */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "TOS Length:0x%X ", + pack_class_rule->u8IPTypeOfServiceLength); + if (pack_class_rule->u8IPTypeOfServiceLength == 3) { + pstClassifierEntry->ucIPTypeOfServiceLength = + pack_class_rule->u8IPTypeOfServiceLength; + pstClassifierEntry->ucTosLow = + pack_class_rule->u8IPTypeOfService[0]; + pstClassifierEntry->ucTosHigh = + pack_class_rule->u8IPTypeOfService[1]; + pstClassifierEntry->ucTosMask = + pack_class_rule->u8IPTypeOfService[2]; + pstClassifierEntry->bTOSValid = TRUE; + } + if (pack_class_rule->u8Protocol == 0) { + /* we didn't get protocol field filled in by the BS */ + pstClassifierEntry->ucProtocolLength = 0; + } else { + pstClassifierEntry->ucProtocolLength = 1; /* 1 valid protocol */ + } + + pstClassifierEntry->ucProtocol[0] = pack_class_rule->u8Protocol; + pstClassifierEntry->u8ClassifierRulePriority = + pack_class_rule->u8ClassifierRulePriority; + + /* store the classifier rule ID and set this classifier entry as valid */ + pstClassifierEntry->ucDirection = + Adapter->PackInfo[uiSearchRuleIndex].ucDirection; + pstClassifierEntry->uiClassifierRuleIndex = + ntohs(pack_class_rule->u16PacketClassificationRuleIndex); + pstClassifierEntry->usVCID_Value = + Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value; + pstClassifierEntry->ulSFID = + Adapter->PackInfo[uiSearchRuleIndex].ulSFID; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Search Index %d Dir: %d, Index: %d, Vcid: %d\n", + uiSearchRuleIndex, + pstClassifierEntry->ucDirection, + pstClassifierEntry->uiClassifierRuleIndex, + pstClassifierEntry->usVCID_Value); + + if (pack_class_rule->u8AssociatedPHSI) + pstClassifierEntry->u8AssociatedPHSI = + pack_class_rule->u8AssociatedPHSI; + + /* Copy ETH CS Parameters */ + pstClassifierEntry->ucEthCSSrcMACLen = + (pack_class_rule->u8EthernetSourceMACAddressLength); + memcpy(pstClassifierEntry->au8EThCSSrcMAC, + pack_class_rule->u8EthernetSourceMACAddress, + MAC_ADDRESS_SIZE); + memcpy(pstClassifierEntry->au8EThCSSrcMACMask, + pack_class_rule->u8EthernetSourceMACAddress + + MAC_ADDRESS_SIZE, MAC_ADDRESS_SIZE); + pstClassifierEntry->ucEthCSDestMACLen = + (pack_class_rule->u8EthernetDestMacAddressLength); + memcpy(pstClassifierEntry->au8EThCSDestMAC, + pack_class_rule->u8EthernetDestMacAddress, + MAC_ADDRESS_SIZE); + memcpy(pstClassifierEntry->au8EThCSDestMACMask, + pack_class_rule->u8EthernetDestMacAddress + + MAC_ADDRESS_SIZE, MAC_ADDRESS_SIZE); + pstClassifierEntry->ucEtherTypeLen = + (pack_class_rule->u8EthertypeLength); + memcpy(pstClassifierEntry->au8EthCSEtherType, + pack_class_rule->u8Ethertype, + NUM_ETHERTYPE_BYTES); + memcpy(pstClassifierEntry->usUserPriority, + &pack_class_rule->u16UserPriority, 2); + pstClassifierEntry->usVLANID = + ntohs(pack_class_rule->u16VLANID); + pstClassifierEntry->usValidityBitMap = + ntohs(pack_class_rule->u16ValidityBitMap); + + pstClassifierEntry->bUsed = TRUE; + } +} + +/* + * @ingroup ctrl_pkt_functions + */ +static inline VOID DeleteClassifierRuleFromSF(struct bcm_mini_adapter *Adapter, + UINT uiSearchRuleIndex, UINT nClassifierIndex) +{ + struct bcm_classifier_rule *pstClassifierEntry = NULL; + B_UINT16 u16PacketClassificationRuleIndex; + USHORT usVCID; + /* VOID *pvPhsContext = NULL; */ + /*ULONG ulPhsStatus; */ + + usVCID = Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value; + + if (nClassifierIndex > MAX_CLASSIFIERS-1) + return; + + if (usVCID == 0) + return; + + u16PacketClassificationRuleIndex = + Adapter->astClassifierTable[nClassifierIndex].uiClassifierRuleIndex; + pstClassifierEntry = &Adapter->astClassifierTable[nClassifierIndex]; + if (pstClassifierEntry) { + pstClassifierEntry->bUsed = false; + pstClassifierEntry->uiClassifierRuleIndex = 0; + memset(pstClassifierEntry, 0, + sizeof(struct bcm_classifier_rule)); + + /* Delete the PHS Rule for this classifier */ + PhsDeleteClassifierRule(&Adapter->stBCMPhsContext, usVCID, + u16PacketClassificationRuleIndex); + } +} + +/* + * @ingroup ctrl_pkt_functions + */ +VOID DeleteAllClassifiersForSF(struct bcm_mini_adapter *Adapter, + UINT uiSearchRuleIndex) +{ + struct bcm_classifier_rule *pstClassifierEntry = NULL; + int i; + /* B_UINT16 u16PacketClassificationRuleIndex; */ + USHORT ulVCID; + /* VOID *pvPhsContext = NULL; */ + /* ULONG ulPhsStatus; */ + + ulVCID = Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value; + + if (ulVCID == 0) + return; + + for (i = 0; i < MAX_CLASSIFIERS; i++) { + if (Adapter->astClassifierTable[i].usVCID_Value == ulVCID) { + pstClassifierEntry = &Adapter->astClassifierTable[i]; + + if (pstClassifierEntry->bUsed) + DeleteClassifierRuleFromSF(Adapter, + uiSearchRuleIndex, i); + } + } + + /* Delete All Phs Rules Associated with this SF */ + PhsDeleteSFRules(&Adapter->stBCMPhsContext, ulVCID); +} + +/* + * This routinue copies the Connection Management + * related data into the Adapter structure. + * @ingroup ctrl_pkt_functions + */ +static VOID CopyToAdapter(register struct bcm_mini_adapter *Adapter, /* <Pointer to the Adapter structure */ + register struct bcm_connect_mgr_params *psfLocalSet, /* Pointer to the connection manager parameters structure */ + register UINT uiSearchRuleIndex, /* <Index of Queue, to which this data belongs */ + register UCHAR ucDsxType, + struct bcm_add_indication_alt *pstAddIndication) { + + /* UCHAR ucProtocolLength = 0; */ + ULONG ulSFID; + UINT nClassifierIndex = 0; + enum E_CLASSIFIER_ACTION eClassifierAction = eInvalidClassifierAction; + B_UINT16 u16PacketClassificationRuleIndex = 0; + int i; + struct bcm_convergence_types *psfCSType = NULL; + struct bcm_phs_rule sPhsRule; + struct bcm_packet_info *curr_packinfo = + &Adapter->PackInfo[uiSearchRuleIndex]; + USHORT uVCID = curr_packinfo->usVCID_Value; + UINT UGIValue = 0; + + curr_packinfo->bValid = TRUE; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Search Rule Index = %d\n", uiSearchRuleIndex); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "%s: SFID= %x ", __func__, ntohl(psfLocalSet->u32SFID)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Updating Queue %d", uiSearchRuleIndex); + + ulSFID = ntohl(psfLocalSet->u32SFID); + /* Store IP Version used */ + /* Get The Version Of IP used (IPv6 or IPv4) from CSSpecification field of SF */ + + curr_packinfo->bIPCSSupport = 0; + curr_packinfo->bEthCSSupport = 0; + + /* Enable IP/ETh CS Support As Required */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "CopyToAdapter : u8CSSpecification : %X\n", + psfLocalSet->u8CSSpecification); + switch (psfLocalSet->u8CSSpecification) { + case eCSPacketIPV4: + curr_packinfo->bIPCSSupport = IPV4_CS; + break; + case eCSPacketIPV6: + curr_packinfo->bIPCSSupport = IPV6_CS; + break; + case eCS802_3PacketEthernet: + case eCS802_1QPacketVLAN: + curr_packinfo->bEthCSSupport = ETH_CS_802_3; + break; + case eCSPacketIPV4Over802_1QVLAN: + case eCSPacketIPV4Over802_3Ethernet: + curr_packinfo->bIPCSSupport = IPV4_CS; + curr_packinfo->bEthCSSupport = ETH_CS_802_3; + break; + case eCSPacketIPV6Over802_1QVLAN: + case eCSPacketIPV6Over802_3Ethernet: + curr_packinfo->bIPCSSupport = IPV6_CS; + curr_packinfo->bEthCSSupport = ETH_CS_802_3; + break; + default: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Error in value of CS Classification.. setting default to IP CS\n"); + curr_packinfo->bIPCSSupport = IPV4_CS; + break; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "CopyToAdapter : Queue No : %X ETH CS Support : %X , IP CS Support : %X\n", + uiSearchRuleIndex, + curr_packinfo->bEthCSSupport, + curr_packinfo->bIPCSSupport); + + /* Store IP Version used */ + /* Get The Version Of IP used (IPv6 or IPv4) from CSSpecification field of SF */ + if (curr_packinfo->bIPCSSupport == IPV6_CS) + curr_packinfo->ucIpVersion = IPV6; + else + curr_packinfo->ucIpVersion = IPV4; + + /* To ensure that the ETH CS code doesn't gets executed if the BS doesn't supports ETH CS */ + if (!Adapter->bETHCSEnabled) + curr_packinfo->bEthCSSupport = 0; + + if (psfLocalSet->u8ServiceClassNameLength > 0 && psfLocalSet->u8ServiceClassNameLength < 32) + memcpy(curr_packinfo->ucServiceClassName, + psfLocalSet->u8ServiceClassName, + psfLocalSet->u8ServiceClassNameLength); + + curr_packinfo->u8QueueType = psfLocalSet->u8ServiceFlowSchedulingType; + + if (curr_packinfo->u8QueueType == BE && curr_packinfo->ucDirection) + Adapter->usBestEffortQueueIndex = uiSearchRuleIndex; + + curr_packinfo->ulSFID = ntohl(psfLocalSet->u32SFID); + + curr_packinfo->u8TrafficPriority = psfLocalSet->u8TrafficPriority; + + /* copy all the classifier in the Service Flow param structure */ + for (i = 0; i < psfLocalSet->u8TotalClassifiers; i++) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Classifier index =%d", i); + psfCSType = &psfLocalSet->cConvergenceSLTypes[i]; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Classifier index =%d", i); + + if (psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority) + curr_packinfo->bClassifierPriority = TRUE; + + if (psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority) + curr_packinfo->bClassifierPriority = TRUE; + + if (ucDsxType == DSA_ACK) { + eClassifierAction = eAddClassifier; + } else if (ucDsxType == DSC_ACK) { + switch (psfCSType->u8ClassfierDSCAction) { + case 0: /* DSC Add Classifier */ + eClassifierAction = eAddClassifier; + break; + case 1: /* DSC Replace Classifier */ + eClassifierAction = eReplaceClassifier; + break; + case 2: /* DSC Delete Classifier */ + eClassifierAction = eDeleteClassifier; + break; + default: + eClassifierAction = eInvalidClassifierAction; + } + } + + u16PacketClassificationRuleIndex = ntohs(psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex); + + switch (eClassifierAction) { + case eAddClassifier: + /* Get a Free Classifier Index From Classifier table for this SF to add the Classifier */ + /* Contained in this message */ + nClassifierIndex = SearchClsid(Adapter, + ulSFID, + u16PacketClassificationRuleIndex); + + if (nClassifierIndex > MAX_CLASSIFIERS) { + nClassifierIndex = SearchFreeClsid(Adapter); + if (nClassifierIndex > MAX_CLASSIFIERS) { + /* Failed To get a free Entry */ + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, + CONN_MSG, + DBG_LVL_ALL, + "Error Failed To get a free Classifier Entry"); + break; + } + /* Copy the Classifier Rule for this service flow into our Classifier table maintained per SF. */ + CopyClassifierRuleToSF(Adapter, psfCSType, + uiSearchRuleIndex, + nClassifierIndex); + } else { + /* This Classifier Already Exists and it is invalid to Add Classifier with existing PCRI */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + CONN_MSG, + DBG_LVL_ALL, + "CopyToAdapter: Error The Specified Classifier Already Exists and attempted To Add Classifier with Same PCRI : 0x%x\n", + u16PacketClassificationRuleIndex); + } + break; + case eReplaceClassifier: + /* Get the Classifier Index From Classifier table for this SF and replace existing Classifier */ + /* with the new classifier Contained in this message */ + nClassifierIndex = SearchClsid(Adapter, ulSFID, + u16PacketClassificationRuleIndex); + if (nClassifierIndex > MAX_CLASSIFIERS) { + /* Failed To search the classifier */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + CONN_MSG, DBG_LVL_ALL, + "Error Search for Classifier To be replaced failed"); + break; + } + /* Copy the Classifier Rule for this service flow into our Classifier table maintained per SF. */ + CopyClassifierRuleToSF(Adapter, psfCSType, + uiSearchRuleIndex, nClassifierIndex); + break; + case eDeleteClassifier: + /* Get the Classifier Index From Classifier table for this SF and replace existing Classifier */ + /* with the new classifier Contained in this message */ + nClassifierIndex = SearchClsid(Adapter, ulSFID, + u16PacketClassificationRuleIndex); + if (nClassifierIndex > MAX_CLASSIFIERS) { + /* Failed To search the classifier */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + CONN_MSG, DBG_LVL_ALL, + "Error Search for Classifier To be deleted failed"); + break; + } + + /* Delete This classifier */ + DeleteClassifierRuleFromSF(Adapter, uiSearchRuleIndex, + nClassifierIndex); + break; + default: + /* Invalid Action for classifier */ + break; + } + } + + /* Repeat parsing Classification Entries to process PHS Rules */ + for (i = 0; i < psfLocalSet->u8TotalClassifiers; i++) { + psfCSType = &psfLocalSet->cConvergenceSLTypes[i]; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "psfCSType->u8PhsDSCAction : 0x%x\n", + psfCSType->u8PhsDSCAction); + + switch (psfCSType->u8PhsDSCAction) { + case eDeleteAllPHSRules: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, + DBG_LVL_ALL, + "Deleting All PHS Rules For VCID: 0x%X\n", + uVCID); + + /* Delete All the PHS rules for this Service flow */ + PhsDeleteSFRules(&Adapter->stBCMPhsContext, uVCID); + break; + case eDeletePHSRule: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, + DBG_LVL_ALL, + "PHS DSC Action = Delete PHS Rule\n"); + + if (psfCSType->cPhsRule.u8PHSI) + PhsDeletePHSRule(&Adapter->stBCMPhsContext, + uVCID, + psfCSType->cCPacketClassificationRule.u8AssociatedPHSI); + + break; + default: + if (ucDsxType == DSC_ACK) { + /* BCM_DEBUG_PRINT(CONN_MSG,("Invalid PHS DSC Action For DSC\n",psfCSType->cPhsRule.u8PHSI)); */ + break; /* FOr DSC ACK Case PHS DSC Action must be in valid set */ + } + /* Proceed To Add PHS rule for DSA_ACK case even if PHS DSC action is unspecified */ + /* No Break Here . Intentionally! */ + + case eAddPHSRule: + case eSetPHSRule: + if (psfCSType->cPhsRule.u8PHSI) { + /* Apply This PHS Rule to all classifiers whose Associated PHSI Match */ + apply_phs_rule_to_all_classifiers(Adapter, + uiSearchRuleIndex, + uVCID, + &sPhsRule, + &psfCSType->cPhsRule, + pstAddIndication); + } + break; + } + } + + if (psfLocalSet->u32MaxSustainedTrafficRate == 0) { + /* No Rate Limit . Set Max Sustained Traffic Rate to Maximum */ + curr_packinfo->uiMaxAllowedRate = WIMAX_MAX_ALLOWED_RATE; + } else if (ntohl(psfLocalSet->u32MaxSustainedTrafficRate) > WIMAX_MAX_ALLOWED_RATE) { + /* Too large Allowed Rate specified. Limiting to Wi Max Allowed rate */ + curr_packinfo->uiMaxAllowedRate = WIMAX_MAX_ALLOWED_RATE; + } else { + curr_packinfo->uiMaxAllowedRate = + ntohl(psfLocalSet->u32MaxSustainedTrafficRate); + } + + curr_packinfo->uiMaxLatency = ntohl(psfLocalSet->u32MaximumLatency); + if (curr_packinfo->uiMaxLatency == 0) /* 0 should be treated as infinite */ + curr_packinfo->uiMaxLatency = MAX_LATENCY_ALLOWED; + + if ((curr_packinfo->u8QueueType == ERTPS || + curr_packinfo->u8QueueType == UGS)) + UGIValue = ntohs(psfLocalSet->u16UnsolicitedGrantInterval); + + if (UGIValue == 0) + UGIValue = DEFAULT_UG_INTERVAL; + + /* + * For UGI based connections... + * DEFAULT_UGI_FACTOR*UGIInterval worth of data is the max token count at host... + * The extra amount of token is to ensure that a large amount of jitter won't have loss in throughput... + * In case of non-UGI based connection, 200 frames worth of data is the max token count at host... + */ + curr_packinfo->uiMaxBucketSize = + (DEFAULT_UGI_FACTOR*curr_packinfo->uiMaxAllowedRate*UGIValue)/1000; + + if (curr_packinfo->uiMaxBucketSize < WIMAX_MAX_MTU*8) { + UINT UGIFactor = 0; + /* Special Handling to ensure the biggest size of packet can go out from host to FW as follows: + * 1. Any packet from Host to FW can go out in different packet size. + * 2. So in case the Bucket count is smaller than MTU, the packets of size (Size > TokenCount), will get dropped. + * 3. We can allow packets of MaxSize from Host->FW that can go out from FW in multiple SDUs by fragmentation at Wimax Layer + */ + UGIFactor = (curr_packinfo->uiMaxLatency/UGIValue + 1); + + if (UGIFactor > DEFAULT_UGI_FACTOR) + curr_packinfo->uiMaxBucketSize = + (UGIFactor*curr_packinfo->uiMaxAllowedRate*UGIValue)/1000; + + if (curr_packinfo->uiMaxBucketSize > WIMAX_MAX_MTU*8) + curr_packinfo->uiMaxBucketSize = WIMAX_MAX_MTU*8; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "LAT: %d, UGI: %d\n", curr_packinfo->uiMaxLatency, + UGIValue); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "uiMaxAllowedRate: 0x%x, u32MaxSustainedTrafficRate: 0x%x ,uiMaxBucketSize: 0x%x", + curr_packinfo->uiMaxAllowedRate, + ntohl(psfLocalSet->u32MaxSustainedTrafficRate), + curr_packinfo->uiMaxBucketSize); + + /* copy the extended SF Parameters to Support MIBS */ + CopyMIBSExtendedSFParameters(Adapter, psfLocalSet, uiSearchRuleIndex); + + /* store header suppression enabled flag per SF */ + curr_packinfo->bHeaderSuppressionEnabled = + !(psfLocalSet->u8RequesttransmissionPolicy & + MASK_DISABLE_HEADER_SUPPRESSION); + + kfree(curr_packinfo->pstSFIndication); + curr_packinfo->pstSFIndication = pstAddIndication; + + /* Re Sort the SF list in PackInfo according to Traffic Priority */ + SortPackInfo(Adapter); + + /* Re Sort the Classifier Rules table and re - arrange + * according to Classifier Rule Priority + */ + SortClassifiers(Adapter); + DumpPhsRules(&Adapter->stBCMPhsContext); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "%s <=====", __func__); +} + +/*********************************************************************** + * Function - DumpCmControlPacket + * + * Description - This routinue Dumps the Contents of the AddIndication + * Structure in the Connection Management Control Packet + * + * Parameter - pvBuffer: Pointer to the buffer containing the + * AddIndication data. + * + * Returns - None + *************************************************************************/ +static VOID DumpCmControlPacket(PVOID pvBuffer) +{ + int uiLoopIndex; + int nIndex; + struct bcm_add_indication_alt *pstAddIndication; + UINT nCurClassifierCnt; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + pstAddIndication = pvBuffer; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "======>"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Type: 0x%X", pstAddIndication->u8Type); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Direction: 0x%X", pstAddIndication->u8Direction); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16TID: 0x%X", ntohs(pstAddIndication->u16TID)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", ntohs(pstAddIndication->u16CID)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16VCID: 0x%X", ntohs(pstAddIndication->u16VCID)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " AuthorizedSet--->"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32SFID: 0x%X", htonl(pstAddIndication->sfAuthorizedSet.u32SFID)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", htons(pstAddIndication->sfAuthorizedSet.u16CID)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassNameLength: 0x%X", + pstAddIndication->sfAuthorizedSet.u8ServiceClassNameLength); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassName: 0x%X ,0x%X , 0x%X, 0x%X, 0x%X, 0x%X", + pstAddIndication->sfAuthorizedSet.u8ServiceClassName[0], + pstAddIndication->sfAuthorizedSet.u8ServiceClassName[1], + pstAddIndication->sfAuthorizedSet.u8ServiceClassName[2], + pstAddIndication->sfAuthorizedSet.u8ServiceClassName[3], + pstAddIndication->sfAuthorizedSet.u8ServiceClassName[4], + pstAddIndication->sfAuthorizedSet.u8ServiceClassName[5]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8MBSService: 0x%X", pstAddIndication->sfAuthorizedSet.u8MBSService); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8QosParamSet: 0x%X", pstAddIndication->sfAuthorizedSet.u8QosParamSet); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficPriority: 0x%X, %p", + pstAddIndication->sfAuthorizedSet.u8TrafficPriority, &pstAddIndication->sfAuthorizedSet.u8TrafficPriority); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaxSustainedTrafficRate: 0x%X 0x%p", + pstAddIndication->sfAuthorizedSet.u32MaxSustainedTrafficRate, + &pstAddIndication->sfAuthorizedSet.u32MaxSustainedTrafficRate); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaxTrafficBurst: 0x%X", pstAddIndication->sfAuthorizedSet.u32MaxTrafficBurst); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate : 0x%X", + pstAddIndication->sfAuthorizedSet.u32MinReservedTrafficRate); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParamLength: 0x%X", + pstAddIndication->sfAuthorizedSet.u8VendorSpecificQoSParamLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParam: 0x%X", + pstAddIndication->sfAuthorizedSet.u8VendorSpecificQoSParam[0]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceFlowSchedulingType: 0x%X", + pstAddIndication->sfAuthorizedSet.u8ServiceFlowSchedulingType); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32ToleratedJitter: 0x%X", pstAddIndication->sfAuthorizedSet.u32ToleratedJitter); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaximumLatency: 0x%X", pstAddIndication->sfAuthorizedSet.u32MaximumLatency); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8FixedLengthVSVariableLengthSDUIndicator: 0x%X", + pstAddIndication->sfAuthorizedSet.u8FixedLengthVSVariableLengthSDUIndicator); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8SDUSize: 0x%X", pstAddIndication->sfAuthorizedSet.u8SDUSize); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16TargetSAID: 0x%X", pstAddIndication->sfAuthorizedSet.u16TargetSAID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ARQEnable: 0x%X", pstAddIndication->sfAuthorizedSet.u8ARQEnable); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQWindowSize: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQWindowSize); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQRetryTxTimeOut: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQRetryTxTimeOut); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQRetryRxTimeOut: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQRetryRxTimeOut); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQBlockLifeTime: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQBlockLifeTime); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQSyncLossTimeOut: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQSyncLossTimeOut); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ARQDeliverInOrder: 0x%X", pstAddIndication->sfAuthorizedSet.u8ARQDeliverInOrder); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQRxPurgeTimeOut: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQRxPurgeTimeOut); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQBlockSize: 0x%X", pstAddIndication->sfAuthorizedSet.u16ARQBlockSize); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8CSSpecification: 0x%X", pstAddIndication->sfAuthorizedSet.u8CSSpecification); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TypeOfDataDeliveryService: 0x%X", + pstAddIndication->sfAuthorizedSet.u8TypeOfDataDeliveryService); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16SDUInterArrivalTime: 0x%X", pstAddIndication->sfAuthorizedSet.u16SDUInterArrivalTime); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16TimeBase: 0x%X", pstAddIndication->sfAuthorizedSet.u16TimeBase); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8PagingPreference: 0x%X", pstAddIndication->sfAuthorizedSet.u8PagingPreference); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16UnsolicitedPollingInterval: 0x%X", + pstAddIndication->sfAuthorizedSet.u16UnsolicitedPollingInterval); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "sfAuthorizedSet.u8HARQChannelMapping %x %x %x ", + *(unsigned int *)pstAddIndication->sfAuthorizedSet.u8HARQChannelMapping, + *(unsigned int *)&pstAddIndication->sfAuthorizedSet.u8HARQChannelMapping[4], + *(USHORT *)&pstAddIndication->sfAuthorizedSet.u8HARQChannelMapping[8]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficIndicationPreference: 0x%X", + pstAddIndication->sfAuthorizedSet.u8TrafficIndicationPreference); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " Total Classifiers Received: 0x%X", pstAddIndication->sfAuthorizedSet.u8TotalClassifiers); + + nCurClassifierCnt = pstAddIndication->sfAuthorizedSet.u8TotalClassifiers; + if (nCurClassifierCnt > MAX_CLASSIFIERS_IN_SF) + nCurClassifierCnt = MAX_CLASSIFIERS_IN_SF; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "pstAddIndication->sfAuthorizedSet.bValid %d", pstAddIndication->sfAuthorizedSet.bValid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "pstAddIndication->sfAuthorizedSet.u16MacOverhead %x", pstAddIndication->sfAuthorizedSet.u16MacOverhead); + if (!pstAddIndication->sfAuthorizedSet.bValid) + pstAddIndication->sfAuthorizedSet.bValid = 1; + for (nIndex = 0; nIndex < nCurClassifierCnt; nIndex++) { + struct bcm_convergence_types *psfCSType = NULL; + psfCSType = &pstAddIndication->sfAuthorizedSet.cConvergenceSLTypes[nIndex]; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "psfCSType = %p", psfCSType); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "CCPacketClassificationRuleSI====>"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ClassifierRulePriority: 0x%X ", + psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPTypeOfServiceLength: 0x%X ", + psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPTypeOfService[3]: 0x%X ,0x%X ,0x%X ", + psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0], + psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1], + psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]); + + for (uiLoopIndex = 0; uiLoopIndex < 1; uiLoopIndex++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Protocol: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8Protocol); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPMaskedSourceAddressLength: 0x%X ", + psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddressLength); + + for (uiLoopIndex = 0; uiLoopIndex < 32; uiLoopIndex++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPMaskedSourceAddress[32]: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddress[uiLoopIndex]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPDestinationAddressLength: 0x%X ", + psfCSType->cCPacketClassificationRule.u8IPDestinationAddressLength); + + for (uiLoopIndex = 0; uiLoopIndex < 32; uiLoopIndex++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPDestinationAddress[32]: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8IPDestinationAddress[uiLoopIndex]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolSourcePortRangeLength:0x%X ", + psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: 0x%02X ,0x%02X ,0x%02X ,0x%02X ", + psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[0], + psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[1], + psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[2], + psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[3]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRangeLength: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: 0x%02X ,0x%02X ,0x%02X ,0x%02X ", + psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[0], + psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[1], + psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[2], + psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[3]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetDestMacAddressLength: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8EthernetDestMacAddress[6]: %pM", + psfCSType->cCPacketClassificationRule. + u8EthernetDestMacAddress); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetSourceMACAddressLength: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8EthernetSourceMACAddress[6]: %pM", + psfCSType->cCPacketClassificationRule. + u8EthernetSourceMACAddress); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthertypeLength: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8EthertypeLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Ethertype[3]: 0x%02X ,0x%02X ,0x%02X ", + psfCSType->cCPacketClassificationRule.u8Ethertype[0], + psfCSType->cCPacketClassificationRule.u8Ethertype[1], + psfCSType->cCPacketClassificationRule.u8Ethertype[2]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16UserPriority: 0x%X ", psfCSType->cCPacketClassificationRule.u16UserPriority); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16VLANID: 0x%X ", psfCSType->cCPacketClassificationRule.u16VLANID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8AssociatedPHSI: 0x%02X ", psfCSType->cCPacketClassificationRule.u8AssociatedPHSI); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16PacketClassificationRuleIndex: 0x%X ", + psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificClassifierParamLength: 0x%X ", + psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParamLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificClassifierParam[1]: 0x%X ", + psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParam[0]); +#ifdef VERSION_D5 + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLableLength: 0x%X ", + psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x%*ph ", + 6, psfCSType->cCPacketClassificationRule. + u8IPv6FlowLable); +#endif + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "bValid: 0x%02X", pstAddIndication->sfAuthorizedSet.bValid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "AdmittedSet--->"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32SFID: 0x%X", pstAddIndication->sfAdmittedSet.u32SFID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", pstAddIndication->sfAdmittedSet.u16CID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassNameLength: 0x%X", + pstAddIndication->sfAdmittedSet.u8ServiceClassNameLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, + "u8ServiceClassName: 0x%*ph", + 6, pstAddIndication->sfAdmittedSet.u8ServiceClassName); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8MBSService: 0x%02X", pstAddIndication->sfAdmittedSet.u8MBSService); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8QosParamSet: 0x%02X", pstAddIndication->sfAdmittedSet.u8QosParamSet); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficPriority: 0x%02X", pstAddIndication->sfAdmittedSet.u8TrafficPriority); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaxTrafficBurst: 0x%X", pstAddIndication->sfAdmittedSet.u32MaxTrafficBurst); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate: 0x%X", + pstAddIndication->sfAdmittedSet.u32MinReservedTrafficRate); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParamLength: 0x%02X", + pstAddIndication->sfAdmittedSet.u8VendorSpecificQoSParamLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParam: 0x%02X", + pstAddIndication->sfAdmittedSet.u8VendorSpecificQoSParam[0]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceFlowSchedulingType: 0x%02X", + pstAddIndication->sfAdmittedSet.u8ServiceFlowSchedulingType); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32ToleratedJitter: 0x%X", pstAddIndication->sfAdmittedSet.u32ToleratedJitter); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaximumLatency: 0x%X", pstAddIndication->sfAdmittedSet.u32MaximumLatency); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8FixedLengthVSVariableLengthSDUIndicator: 0x%02X", + pstAddIndication->sfAdmittedSet.u8FixedLengthVSVariableLengthSDUIndicator); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8SDUSize: 0x%02X", pstAddIndication->sfAdmittedSet.u8SDUSize); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16TargetSAID: 0x%02X", pstAddIndication->sfAdmittedSet.u16TargetSAID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ARQEnable: 0x%02X", pstAddIndication->sfAdmittedSet.u8ARQEnable); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQWindowSize: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQWindowSize); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQRetryTxTimeOut: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQRetryTxTimeOut); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQRetryRxTimeOut: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQRetryRxTimeOut); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQBlockLifeTime: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQBlockLifeTime); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQSyncLossTimeOut: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQSyncLossTimeOut); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ARQDeliverInOrder: 0x%02X", pstAddIndication->sfAdmittedSet.u8ARQDeliverInOrder); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQRxPurgeTimeOut: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQRxPurgeTimeOut); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16ARQBlockSize: 0x%X", pstAddIndication->sfAdmittedSet.u16ARQBlockSize); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8CSSpecification: 0x%02X", pstAddIndication->sfAdmittedSet.u8CSSpecification); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TypeOfDataDeliveryService: 0x%02X", + pstAddIndication->sfAdmittedSet.u8TypeOfDataDeliveryService); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16SDUInterArrivalTime: 0x%X", pstAddIndication->sfAdmittedSet.u16SDUInterArrivalTime); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16TimeBase: 0x%X", pstAddIndication->sfAdmittedSet.u16TimeBase); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8PagingPreference: 0x%X", pstAddIndication->sfAdmittedSet.u8PagingPreference); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficIndicationPreference: 0x%02X", + pstAddIndication->sfAdmittedSet.u8TrafficIndicationPreference); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " Total Classifiers Received: 0x%X", pstAddIndication->sfAdmittedSet.u8TotalClassifiers); + + nCurClassifierCnt = pstAddIndication->sfAdmittedSet.u8TotalClassifiers; + if (nCurClassifierCnt > MAX_CLASSIFIERS_IN_SF) + nCurClassifierCnt = MAX_CLASSIFIERS_IN_SF; + + for (nIndex = 0; nIndex < nCurClassifierCnt; nIndex++) { + struct bcm_convergence_types *psfCSType = NULL; + + psfCSType = &pstAddIndication->sfAdmittedSet.cConvergenceSLTypes[nIndex]; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " CCPacketClassificationRuleSI====>"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ClassifierRulePriority: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPTypeOfServiceLength: 0x%02X", + psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8IPTypeOfService[3]: 0x%*ph", + 3, psfCSType->cCPacketClassificationRule. + u8IPTypeOfService); + for (uiLoopIndex = 0; uiLoopIndex < 1; uiLoopIndex++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Protocol: 0x%02X ", psfCSType->cCPacketClassificationRule.u8Protocol); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPMaskedSourceAddressLength: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddressLength); + + for (uiLoopIndex = 0; uiLoopIndex < 32; uiLoopIndex++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPMaskedSourceAddress[32]: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8IPMaskedSourceAddress[uiLoopIndex]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPDestinationAddressLength: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8IPDestinationAddressLength); + + for (uiLoopIndex = 0; uiLoopIndex < 32; uiLoopIndex++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPDestinationAddress[32]: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8IPDestinationAddress[uiLoopIndex]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolSourcePortRangeLength: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: 0x%*ph ", + 4, psfCSType->cCPacketClassificationRule. + u8ProtocolSourcePortRange); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRangeLength: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: 0x%*ph ", + 4, psfCSType->cCPacketClassificationRule. + u8ProtocolDestPortRange); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetDestMacAddressLength: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8EthernetDestMacAddress[6]: %pM", + psfCSType->cCPacketClassificationRule. + u8EthernetDestMacAddress); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetSourceMACAddressLength: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8EthernetSourceMACAddress[6]: %pM", + psfCSType->cCPacketClassificationRule. + u8EthernetSourceMACAddress); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthertypeLength: 0x%02X ", psfCSType->cCPacketClassificationRule.u8EthertypeLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8Ethertype[3]: 0x%*ph", + 3, psfCSType->cCPacketClassificationRule. + u8Ethertype); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16UserPriority: 0x%X ", psfCSType->cCPacketClassificationRule.u16UserPriority); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16VLANID: 0x%X ", psfCSType->cCPacketClassificationRule.u16VLANID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8AssociatedPHSI: 0x%02X ", psfCSType->cCPacketClassificationRule.u8AssociatedPHSI); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16PacketClassificationRuleIndex: 0x%X ", + psfCSType->cCPacketClassificationRule.u16PacketClassificationRuleIndex); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificClassifierParamLength: 0x%02X", + psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParamLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificClassifierParam[1]: 0x%02X ", + psfCSType->cCPacketClassificationRule.u8VendorSpecificClassifierParam[0]); +#ifdef VERSION_D5 + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLableLength: 0x%X ", + psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x%*ph ", + 6, psfCSType->cCPacketClassificationRule. + u8IPv6FlowLable); +#endif + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "bValid: 0x%X", pstAddIndication->sfAdmittedSet.bValid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " ActiveSet--->"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32SFID: 0x%X", pstAddIndication->sfActiveSet.u32SFID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", pstAddIndication->sfActiveSet.u16CID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassNameLength: 0x%X", pstAddIndication->sfActiveSet.u8ServiceClassNameLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, + "u8ServiceClassName: 0x%*ph", + 6, pstAddIndication->sfActiveSet.u8ServiceClassName); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8MBSService: 0x%02X", pstAddIndication->sfActiveSet.u8MBSService); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8QosParamSet: 0x%02X", pstAddIndication->sfActiveSet.u8QosParamSet); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8TrafficPriority: 0x%02X", pstAddIndication->sfActiveSet.u8TrafficPriority); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaxTrafficBurst: 0x%X", pstAddIndication->sfActiveSet.u32MaxTrafficBurst); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MinReservedTrafficRate: 0x%X", + pstAddIndication->sfActiveSet.u32MinReservedTrafficRate); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParamLength: 0x%02X", + pstAddIndication->sfActiveSet.u8VendorSpecificQoSParamLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8VendorSpecificQoSParam: 0x%02X", + pstAddIndication->sfActiveSet.u8VendorSpecificQoSParam[0]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceFlowSchedulingType: 0x%02X", + pstAddIndication->sfActiveSet.u8ServiceFlowSchedulingType); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32ToleratedJitter: 0x%X", pstAddIndication->sfActiveSet.u32ToleratedJitter); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32MaximumLatency: 0x%X", pstAddIndication->sfActiveSet.u32MaximumLatency); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8FixedLengthVSVariableLengthSDUIndicator: 0x%02X", + pstAddIndication->sfActiveSet.u8FixedLengthVSVariableLengthSDUIndicator); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8SDUSize: 0x%X", pstAddIndication->sfActiveSet.u8SDUSize); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16TargetSAID: 0x%X", pstAddIndication->sfActiveSet.u16TargetSAID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8ARQEnable: 0x%X", pstAddIndication->sfActiveSet.u8ARQEnable); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQWindowSize: 0x%X", pstAddIndication->sfActiveSet.u16ARQWindowSize); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQRetryTxTimeOut: 0x%X", pstAddIndication->sfActiveSet.u16ARQRetryTxTimeOut); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQRetryRxTimeOut: 0x%X", pstAddIndication->sfActiveSet.u16ARQRetryRxTimeOut); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQBlockLifeTime: 0x%X", pstAddIndication->sfActiveSet.u16ARQBlockLifeTime); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQSyncLossTimeOut: 0x%X", pstAddIndication->sfActiveSet.u16ARQSyncLossTimeOut); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8ARQDeliverInOrder: 0x%X", pstAddIndication->sfActiveSet.u8ARQDeliverInOrder); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQRxPurgeTimeOut: 0x%X", pstAddIndication->sfActiveSet.u16ARQRxPurgeTimeOut); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16ARQBlockSize: 0x%X", pstAddIndication->sfActiveSet.u16ARQBlockSize); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8CSSpecification: 0x%X", pstAddIndication->sfActiveSet.u8CSSpecification); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8TypeOfDataDeliveryService: 0x%X", + pstAddIndication->sfActiveSet.u8TypeOfDataDeliveryService); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16SDUInterArrivalTime: 0x%X", pstAddIndication->sfActiveSet.u16SDUInterArrivalTime); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u16TimeBase: 0x%X", pstAddIndication->sfActiveSet.u16TimeBase); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8PagingPreference: 0x%X", pstAddIndication->sfActiveSet.u8PagingPreference); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " u8TrafficIndicationPreference: 0x%X", + pstAddIndication->sfActiveSet.u8TrafficIndicationPreference); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " Total Classifiers Received: 0x%X", pstAddIndication->sfActiveSet.u8TotalClassifiers); + + nCurClassifierCnt = pstAddIndication->sfActiveSet.u8TotalClassifiers; + if (nCurClassifierCnt > MAX_CLASSIFIERS_IN_SF) + nCurClassifierCnt = MAX_CLASSIFIERS_IN_SF; + + for (nIndex = 0; nIndex < nCurClassifierCnt; nIndex++) { + struct bcm_convergence_types *psfCSType = NULL; + struct bcm_packet_class_rules *clsRule = NULL; + + psfCSType = &pstAddIndication->sfActiveSet.cConvergenceSLTypes[nIndex]; + clsRule = &psfCSType->cCPacketClassificationRule; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, " CCPacketClassificationRuleSI====>"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, " u8ClassifierRulePriority: 0x%X ", + clsRule->u8ClassifierRulePriority); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, " u8IPTypeOfServiceLength: 0x%X ", + clsRule->u8IPTypeOfServiceLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8IPTypeOfService[3]: 0x%X ,0x%X ,0x%X ", + clsRule->u8IPTypeOfService[0], + clsRule->u8IPTypeOfService[1], + clsRule->u8IPTypeOfService[2]); + + for (uiLoopIndex = 0; uiLoopIndex < 1; uiLoopIndex++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8Protocol: 0x%X ", + clsRule->u8Protocol); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + "u8IPMaskedSourceAddressLength: 0x%X ", + clsRule->u8IPMaskedSourceAddressLength); + + for (uiLoopIndex = 0; uiLoopIndex < 32; uiLoopIndex++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + "u8IPMaskedSourceAddress[32]: 0x%X ", + clsRule->u8IPMaskedSourceAddress[uiLoopIndex]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + "u8IPDestinationAddressLength: 0x%02X ", + clsRule->u8IPDestinationAddressLength); + + for (uiLoopIndex = 0; uiLoopIndex < 32; uiLoopIndex++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8IPDestinationAddress[32]:0x%X ", + clsRule->u8IPDestinationAddress[uiLoopIndex]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8ProtocolSourcePortRangeLength: 0x%X ", + clsRule->u8ProtocolSourcePortRangeLength); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8ProtocolSourcePortRange[4]: 0x%X ,0x%X ,0x%X ,0x%X ", + clsRule->u8ProtocolSourcePortRange[0], + clsRule->u8ProtocolSourcePortRange[1], + clsRule->u8ProtocolSourcePortRange[2], + clsRule->u8ProtocolSourcePortRange[3]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8ProtocolDestPortRangeLength: 0x%X ", + clsRule->u8ProtocolDestPortRangeLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8ProtocolDestPortRange[4]: 0x%X ,0x%X ,0x%X ,0x%X ", + clsRule->u8ProtocolDestPortRange[0], + clsRule->u8ProtocolDestPortRange[1], + clsRule->u8ProtocolDestPortRange[2], + clsRule->u8ProtocolDestPortRange[3]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8EthernetDestMacAddressLength: 0x%X ", + clsRule->u8EthernetDestMacAddressLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8EthernetDestMacAddress[6]: 0x%X ,0x%X ,0x%X ,0x%X ,0x%X ,0x%X", + clsRule->u8EthernetDestMacAddress[0], + clsRule->u8EthernetDestMacAddress[1], + clsRule->u8EthernetDestMacAddress[2], + clsRule->u8EthernetDestMacAddress[3], + clsRule->u8EthernetDestMacAddress[4], + clsRule->u8EthernetDestMacAddress[5]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8EthernetSourceMACAddressLength: 0x%X ", + clsRule->u8EthernetDestMacAddressLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + "u8EthernetSourceMACAddress[6]: 0x%X ,0x%X ,0x%X ,0x%X ,0x%X ,0x%X", + clsRule->u8EthernetSourceMACAddress[0], + clsRule->u8EthernetSourceMACAddress[1], + clsRule->u8EthernetSourceMACAddress[2], + clsRule->u8EthernetSourceMACAddress[3], + clsRule->u8EthernetSourceMACAddress[4], + clsRule->u8EthernetSourceMACAddress[5]); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, " u8EthertypeLength: 0x%X ", + clsRule->u8EthertypeLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8Ethertype[3]: 0x%X ,0x%X ,0x%X ", + clsRule->u8Ethertype[0], + clsRule->u8Ethertype[1], + clsRule->u8Ethertype[2]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, " u16UserPriority: 0x%X ", + clsRule->u16UserPriority); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, " u16VLANID: 0x%X ", + clsRule->u16VLANID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, " u8AssociatedPHSI: 0x%X ", + clsRule->u8AssociatedPHSI); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u16PacketClassificationRuleIndex:0x%X ", + clsRule->u16PacketClassificationRuleIndex); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8VendorSpecificClassifierParamLength:0x%X ", + clsRule->u8VendorSpecificClassifierParamLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8VendorSpecificClassifierParam[1]:0x%X ", + clsRule->u8VendorSpecificClassifierParam[0]); +#ifdef VERSION_D5 + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, " u8IPv6FlowLableLength: 0x%X ", + clsRule->u8IPv6FlowLableLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, + " u8IPv6FlowLable[6]: 0x%X ,0x%X ,0x%X ,0x%X ,0x%X ,0x%X ", + clsRule->u8IPv6FlowLable[0], + clsRule->u8IPv6FlowLable[1], + clsRule->u8IPv6FlowLable[2], + clsRule->u8IPv6FlowLable[3], + clsRule->u8IPv6FlowLable[4], + clsRule->u8IPv6FlowLable[5]); +#endif + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, + " bValid: 0x%X", pstAddIndication->sfActiveSet.bValid); +} + +static inline ULONG RestoreSFParam(struct bcm_mini_adapter *Adapter, + ULONG ulAddrSFParamSet, PUCHAR pucDestBuffer) +{ + UINT nBytesToRead = sizeof(struct bcm_connect_mgr_params); + + if (ulAddrSFParamSet == 0 || NULL == pucDestBuffer) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Got Param address as 0!!"); + return 0; + } + ulAddrSFParamSet = ntohl(ulAddrSFParamSet); + + /* Read out the SF Param Set At the indicated Location */ + if (rdm(Adapter, ulAddrSFParamSet,(PUCHAR)pucDestBuffer, nBytesToRead) < 0) + return STATUS_FAILURE; + + return 1; +} + +static ULONG StoreSFParam(struct bcm_mini_adapter *Adapter, PUCHAR pucSrcBuffer, + ULONG ulAddrSFParamSet) +{ + UINT nBytesToWrite = sizeof(struct bcm_connect_mgr_params); + int ret = 0; + + if (ulAddrSFParamSet == 0 || NULL == pucSrcBuffer) + return 0; + + ret = wrm(Adapter, ulAddrSFParamSet, (u8 *)pucSrcBuffer, nBytesToWrite); + if (ret < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "%s:%d WRM failed", __func__, __LINE__); + return ret; + } + return 1; +} + +ULONG StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, + PVOID pvBuffer, UINT *puBufferLength) +{ + struct bcm_add_indication_alt *pstAddIndicationAlt = NULL; + struct bcm_add_indication *pstAddIndication = NULL; + struct bcm_del_request *pstDeletionRequest; + UINT uiSearchRuleIndex; + ULONG ulSFID; + + pstAddIndicationAlt = pvBuffer; + + /* + * In case of DSD Req By MS, we should immediately delete this SF so that + * we can stop the further classifying the pkt for this SF. + */ + if (pstAddIndicationAlt->u8Type == DSD_REQ) { + pstDeletionRequest = pvBuffer; + + ulSFID = ntohl(pstDeletionRequest->u32SFID); + uiSearchRuleIndex = SearchSfid(Adapter, ulSFID); + + if (uiSearchRuleIndex < NO_OF_QUEUES) { + deleteSFBySfid(Adapter, uiSearchRuleIndex); + Adapter->u32TotalDSD++; + } + return 1; + } + + if ((pstAddIndicationAlt->u8Type == DSD_RSP) || + (pstAddIndicationAlt->u8Type == DSD_ACK)) { + /* No Special handling send the message as it is */ + return 1; + } + /* For DSA_REQ, only up to "psfAuthorizedSet" parameter should be accessed by driver! */ + + pstAddIndication = kmalloc(sizeof(struct bcm_add_indication), + GFP_KERNEL); + if (pstAddIndication == NULL) + return 0; + + /* AUTHORIZED SET */ + pstAddIndication->psfAuthorizedSet = (struct bcm_connect_mgr_params *) + GetNextTargetBufferLocation(Adapter, + pstAddIndicationAlt->u16TID); + if (!pstAddIndication->psfAuthorizedSet) { + kfree(pstAddIndication); + return 0; + } + + if (StoreSFParam(Adapter, (PUCHAR)&pstAddIndicationAlt->sfAuthorizedSet, + (ULONG)pstAddIndication->psfAuthorizedSet) != 1) { + kfree(pstAddIndication); + return 0; + } + + /* this can't possibly be right */ + pstAddIndication->psfAuthorizedSet = + (struct bcm_connect_mgr_params *) ntohl( + (ULONG)pstAddIndication->psfAuthorizedSet); + + if (pstAddIndicationAlt->u8Type == DSA_REQ) { + struct bcm_add_request AddRequest; + + AddRequest.u8Type = pstAddIndicationAlt->u8Type; + AddRequest.eConnectionDir = pstAddIndicationAlt->u8Direction; + AddRequest.u16TID = pstAddIndicationAlt->u16TID; + AddRequest.u16CID = pstAddIndicationAlt->u16CID; + AddRequest.u16VCID = pstAddIndicationAlt->u16VCID; + AddRequest.psfParameterSet = pstAddIndication->psfAuthorizedSet; + (*puBufferLength) = sizeof(struct bcm_add_request); + memcpy(pvBuffer, &AddRequest, sizeof(struct bcm_add_request)); + kfree(pstAddIndication); + return 1; + } + + /* Since it's not DSA_REQ, we can access all field in pstAddIndicationAlt */ + /* We need to extract the structure from the buffer and pack it differently */ + + pstAddIndication->u8Type = pstAddIndicationAlt->u8Type; + pstAddIndication->eConnectionDir = pstAddIndicationAlt->u8Direction; + pstAddIndication->u16TID = pstAddIndicationAlt->u16TID; + pstAddIndication->u16CID = pstAddIndicationAlt->u16CID; + pstAddIndication->u16VCID = pstAddIndicationAlt->u16VCID; + pstAddIndication->u8CC = pstAddIndicationAlt->u8CC; + + /* ADMITTED SET */ + pstAddIndication->psfAdmittedSet = (struct bcm_connect_mgr_params *) + GetNextTargetBufferLocation(Adapter, + pstAddIndicationAlt->u16TID); + if (!pstAddIndication->psfAdmittedSet) { + kfree(pstAddIndication); + return 0; + } + if (StoreSFParam(Adapter, (PUCHAR)&pstAddIndicationAlt->sfAdmittedSet, + (ULONG)pstAddIndication->psfAdmittedSet) != 1) { + kfree(pstAddIndication); + return 0; + } + + pstAddIndication->psfAdmittedSet = + (struct bcm_connect_mgr_params *) ntohl( + (ULONG) pstAddIndication->psfAdmittedSet); + + /* ACTIVE SET */ + pstAddIndication->psfActiveSet = (struct bcm_connect_mgr_params *) + GetNextTargetBufferLocation(Adapter, + pstAddIndicationAlt->u16TID); + if (!pstAddIndication->psfActiveSet) { + kfree(pstAddIndication); + return 0; + } + if (StoreSFParam(Adapter, (PUCHAR)&pstAddIndicationAlt->sfActiveSet, + (ULONG)pstAddIndication->psfActiveSet) != 1) { + kfree(pstAddIndication); + return 0; + } + + pstAddIndication->psfActiveSet = + (struct bcm_connect_mgr_params *) ntohl( + (ULONG)pstAddIndication->psfActiveSet); + + (*puBufferLength) = sizeof(struct bcm_add_indication); + *(struct bcm_add_indication *)pvBuffer = *pstAddIndication; + kfree(pstAddIndication); + return 1; +} + +static inline struct bcm_add_indication_alt +*RestoreCmControlResponseMessage(register struct bcm_mini_adapter *Adapter, + register PVOID pvBuffer) +{ + ULONG ulStatus = 0; + struct bcm_add_indication *pstAddIndication = NULL; + struct bcm_add_indication_alt *pstAddIndicationDest = NULL; + + pstAddIndication = pvBuffer; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "=====>"); + if ((pstAddIndication->u8Type == DSD_REQ) || + (pstAddIndication->u8Type == DSD_RSP) || + (pstAddIndication->u8Type == DSD_ACK)) + return pvBuffer; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Inside RestoreCmControlResponseMessage "); + /* + * Need to Allocate memory to contain the SUPER Large structures + * Our driver can't create these structures on Stack :( + */ + pstAddIndicationDest = kmalloc(sizeof(struct bcm_add_indication_alt), + GFP_KERNEL); + + if (pstAddIndicationDest) { + memset(pstAddIndicationDest, 0, + sizeof(struct bcm_add_indication_alt)); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, + DBG_LVL_ALL, + "Failed to allocate memory for SF Add Indication Structure "); + return NULL; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "AddIndication-u8Type : 0x%X", + pstAddIndication->u8Type); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "AddIndication-u8Direction : 0x%X", + pstAddIndication->eConnectionDir); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "AddIndication-u8TID : 0x%X", + ntohs(pstAddIndication->u16TID)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "AddIndication-u8CID : 0x%X", + ntohs(pstAddIndication->u16CID)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "AddIndication-u16VCID : 0x%X", + ntohs(pstAddIndication->u16VCID)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "AddIndication-autorized set loc : %p", + pstAddIndication->psfAuthorizedSet); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "AddIndication-admitted set loc : %p", + pstAddIndication->psfAdmittedSet); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "AddIndication-Active set loc : %p", + pstAddIndication->psfActiveSet); + + pstAddIndicationDest->u8Type = pstAddIndication->u8Type; + pstAddIndicationDest->u8Direction = pstAddIndication->eConnectionDir; + pstAddIndicationDest->u16TID = pstAddIndication->u16TID; + pstAddIndicationDest->u16CID = pstAddIndication->u16CID; + pstAddIndicationDest->u16VCID = pstAddIndication->u16VCID; + pstAddIndicationDest->u8CC = pstAddIndication->u8CC; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Restoring Active Set "); + ulStatus = RestoreSFParam(Adapter, + (ULONG)pstAddIndication->psfActiveSet, + (PUCHAR)&pstAddIndicationDest->sfActiveSet); + if (ulStatus != 1) + goto failed_restore_sf_param; + + if (pstAddIndicationDest->sfActiveSet.u8TotalClassifiers > MAX_CLASSIFIERS_IN_SF) + pstAddIndicationDest->sfActiveSet.u8TotalClassifiers = + MAX_CLASSIFIERS_IN_SF; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Restoring Admitted Set "); + ulStatus = RestoreSFParam(Adapter, + (ULONG)pstAddIndication->psfAdmittedSet, + (PUCHAR)&pstAddIndicationDest->sfAdmittedSet); + if (ulStatus != 1) + goto failed_restore_sf_param; + + if (pstAddIndicationDest->sfAdmittedSet.u8TotalClassifiers > MAX_CLASSIFIERS_IN_SF) + pstAddIndicationDest->sfAdmittedSet.u8TotalClassifiers = + MAX_CLASSIFIERS_IN_SF; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Restoring Authorized Set "); + ulStatus = RestoreSFParam(Adapter, + (ULONG)pstAddIndication->psfAuthorizedSet, + (PUCHAR)&pstAddIndicationDest->sfAuthorizedSet); + if (ulStatus != 1) + goto failed_restore_sf_param; + + if (pstAddIndicationDest->sfAuthorizedSet.u8TotalClassifiers > MAX_CLASSIFIERS_IN_SF) + pstAddIndicationDest->sfAuthorizedSet.u8TotalClassifiers = + MAX_CLASSIFIERS_IN_SF; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Dumping the whole raw packet"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "============================================================"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + " pstAddIndicationDest->sfActiveSet size %zx %p", + sizeof(*pstAddIndicationDest), pstAddIndicationDest); + /* BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_OTHERS, CONN_MSG, + * DBG_LVL_ALL, (unsigned char *)pstAddIndicationDest, + * sizeof(*pstAddIndicationDest)); + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "============================================================"); + return pstAddIndicationDest; +failed_restore_sf_param: + kfree(pstAddIndicationDest); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "<====="); + return NULL; +} + +ULONG SetUpTargetDsxBuffers(struct bcm_mini_adapter *Adapter) +{ + ULONG ulTargetDsxBuffersBase = 0; + ULONG ulCntTargetBuffers; + ULONG i; + int Status; + + if (!Adapter) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Adapter was NULL!!!"); + return 0; + } + + if (Adapter->astTargetDsxBuffer[0].ulTargetDsxBuffer) + return 1; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Size of Each DSX Buffer(Also size of connection manager parameters): %zx ", + sizeof(struct bcm_connect_mgr_params)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Reading DSX buffer From Target location %x ", + DSX_MESSAGE_EXCHANGE_BUFFER); + + Status = rdmalt(Adapter, DSX_MESSAGE_EXCHANGE_BUFFER, + (PUINT)&ulTargetDsxBuffersBase, sizeof(UINT)); + if (Status < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "RDM failed!!"); + return 0; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Base Address Of DSX Target Buffer : 0x%lx", + ulTargetDsxBuffersBase); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Tgt Buffer is Now %lx :", ulTargetDsxBuffersBase); + ulCntTargetBuffers = DSX_MESSAGE_EXCHANGE_BUFFER_SIZE / + sizeof(struct bcm_connect_mgr_params); + + Adapter->ulTotalTargetBuffersAvailable = + ulCntTargetBuffers > MAX_TARGET_DSX_BUFFERS ? + MAX_TARGET_DSX_BUFFERS : ulCntTargetBuffers; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + " Total Target DSX Buffer setup %lx ", + Adapter->ulTotalTargetBuffersAvailable); + + for (i = 0; i < Adapter->ulTotalTargetBuffersAvailable; i++) { + Adapter->astTargetDsxBuffer[i].ulTargetDsxBuffer = ulTargetDsxBuffersBase; + Adapter->astTargetDsxBuffer[i].valid = 1; + Adapter->astTargetDsxBuffer[i].tid = 0; + ulTargetDsxBuffersBase += sizeof(struct bcm_connect_mgr_params); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " Target DSX Buffer %lx setup at 0x%lx", + i, Adapter->astTargetDsxBuffer[i].ulTargetDsxBuffer); + } + Adapter->ulCurrentTargetBuffer = 0; + Adapter->ulFreeTargetBufferCnt = Adapter->ulTotalTargetBuffersAvailable; + return 1; +} + +static ULONG GetNextTargetBufferLocation(struct bcm_mini_adapter *Adapter, + B_UINT16 tid) +{ + ULONG dsx_buf; + ULONG idx, max_try; + + if ((Adapter->ulTotalTargetBuffersAvailable == 0) + || (Adapter->ulFreeTargetBufferCnt == 0)) { + ClearTargetDSXBuffer(Adapter, tid, false); + return 0; + } + + idx = Adapter->ulCurrentTargetBuffer; + max_try = Adapter->ulTotalTargetBuffersAvailable; + while ((max_try) && (Adapter->astTargetDsxBuffer[idx].valid != 1)) { + idx = (idx+1) % Adapter->ulTotalTargetBuffersAvailable; + max_try--; + } + + if (max_try == 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "\n GetNextTargetBufferLocation : Error No Free Target DSX Buffers FreeCnt : %lx ", + Adapter->ulFreeTargetBufferCnt); + ClearTargetDSXBuffer(Adapter, tid, false); + return 0; + } + + dsx_buf = Adapter->astTargetDsxBuffer[idx].ulTargetDsxBuffer; + Adapter->astTargetDsxBuffer[idx].valid = 0; + Adapter->astTargetDsxBuffer[idx].tid = tid; + Adapter->ulFreeTargetBufferCnt--; + idx = (idx+1)%Adapter->ulTotalTargetBuffersAvailable; + Adapter->ulCurrentTargetBuffer = idx; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "GetNextTargetBufferLocation :Returning address %lx tid %d\n", + dsx_buf, tid); + + return dsx_buf; +} + +int AllocAdapterDsxBuffer(struct bcm_mini_adapter *Adapter) +{ + /* + * Need to Allocate memory to contain the SUPER Large structures + * Our driver can't create these structures on Stack + */ + Adapter->caDsxReqResp = kmalloc(sizeof(struct bcm_add_indication_alt) + + LEADER_SIZE, GFP_KERNEL); + if (!Adapter->caDsxReqResp) + return -ENOMEM; + + return 0; +} + +int FreeAdapterDsxBuffer(struct bcm_mini_adapter *Adapter) +{ + kfree(Adapter->caDsxReqResp); + return 0; +} + +/* + * @ingroup ctrl_pkt_functions + * This routinue would process the Control responses + * for the Connection Management. + * @return - Queue index for the free SFID else returns Invalid Index. + */ +bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* <Pointer to the Adapter structure */ + PVOID pvBuffer /* Starting Address of the Buffer, that contains the AddIndication Data */) +{ + struct bcm_connect_mgr_params *psfLocalSet = NULL; + struct bcm_add_indication_alt *pstAddIndication = NULL; + struct bcm_change_indication *pstChangeIndication = NULL; + struct bcm_leader *pLeader = NULL; + INT uiSearchRuleIndex = 0; + ULONG ulSFID; + + /* + * Otherwise the message contains a target address from where we need to + * read out the rest of the service flow param structure + */ + pstAddIndication = RestoreCmControlResponseMessage(Adapter, pvBuffer); + if (pstAddIndication == NULL) { + ClearTargetDSXBuffer(Adapter, ((struct bcm_add_indication *)pvBuffer)->u16TID, false); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Error in restoring Service Flow param structure from DSx message"); + return false; + } + + DumpCmControlPacket(pstAddIndication); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "====>"); + pLeader = (struct bcm_leader *)Adapter->caDsxReqResp; + + pLeader->Status = CM_CONTROL_NEWDSX_MULTICLASSIFIER_REQ; + pLeader->Vcid = 0; + + ClearTargetDSXBuffer(Adapter, pstAddIndication->u16TID, false); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "### TID RECEIVED %d\n", pstAddIndication->u16TID); + switch (pstAddIndication->u8Type) { + case DSA_REQ: + pLeader->PLength = sizeof(struct bcm_add_indication_alt); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Sending DSA Response....\n"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSA RESPONSE TO MAC %d", pLeader->PLength); + *((struct bcm_add_indication_alt *)&(Adapter->caDsxReqResp[LEADER_SIZE])) + = *pstAddIndication; + ((struct bcm_add_indication_alt *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSA_RSP; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " VCID = %x", ntohs(pstAddIndication->u16VCID)); + CopyBufferToControlPacket(Adapter, (PVOID)Adapter->caDsxReqResp); + kfree(pstAddIndication); + break; + case DSA_RSP: + pLeader->PLength = sizeof(struct bcm_add_indication_alt); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSA ACK TO MAC %d", + pLeader->PLength); + *((struct bcm_add_indication_alt *)&(Adapter->caDsxReqResp[LEADER_SIZE])) + = *pstAddIndication; + ((struct bcm_add_indication_alt *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSA_ACK; + /* FALLTHROUGH */ + case DSA_ACK: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "VCID:0x%X", + ntohs(pstAddIndication->u16VCID)); + uiSearchRuleIndex = SearchFreeSfid(Adapter); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "uiSearchRuleIndex:0x%X ", + uiSearchRuleIndex); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Direction:0x%X ", + pstAddIndication->u8Direction); + if (uiSearchRuleIndex < NO_OF_QUEUES) { + Adapter->PackInfo[uiSearchRuleIndex].ucDirection = + pstAddIndication->u8Direction; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "bValid:0x%X ", + pstAddIndication->sfActiveSet.bValid); + if (pstAddIndication->sfActiveSet.bValid == TRUE) + Adapter->PackInfo[uiSearchRuleIndex].bActiveSet = TRUE; + + if (pstAddIndication->sfAuthorizedSet.bValid == TRUE) + Adapter->PackInfo[uiSearchRuleIndex].bAuthorizedSet = TRUE; + + if (pstAddIndication->sfAdmittedSet.bValid == TRUE) + Adapter->PackInfo[uiSearchRuleIndex].bAdmittedSet = TRUE; + + if (pstAddIndication->sfActiveSet.bValid == false) { + Adapter->PackInfo[uiSearchRuleIndex].bActive = false; + Adapter->PackInfo[uiSearchRuleIndex].bActivateRequestSent = false; + if (pstAddIndication->sfAdmittedSet.bValid) + psfLocalSet = &pstAddIndication->sfAdmittedSet; + else if (pstAddIndication->sfAuthorizedSet.bValid) + psfLocalSet = &pstAddIndication->sfAuthorizedSet; + } else { + psfLocalSet = &pstAddIndication->sfActiveSet; + Adapter->PackInfo[uiSearchRuleIndex].bActive = TRUE; + } + + if (!psfLocalSet) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "No set is valid\n"); + Adapter->PackInfo[uiSearchRuleIndex].bActive = false; + Adapter->PackInfo[uiSearchRuleIndex].bValid = false; + Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value = 0; + kfree(pstAddIndication); + } else if (psfLocalSet->bValid && (pstAddIndication->u8CC == 0)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSA ACK"); + Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value = ntohs(pstAddIndication->u16VCID); + Adapter->PackInfo[uiSearchRuleIndex].usCID = ntohs(pstAddIndication->u16CID); + + if (UPLINK_DIR == pstAddIndication->u8Direction) + atomic_set(&Adapter->PackInfo[uiSearchRuleIndex].uiPerSFTxResourceCount, DEFAULT_PERSFCOUNT); + + CopyToAdapter(Adapter, psfLocalSet, uiSearchRuleIndex, DSA_ACK, pstAddIndication); + /* don't free pstAddIndication */ + + /* Inside CopyToAdapter, Sorting of all the SFs take place. + * Hence any access to the newly added SF through uiSearchRuleIndex is invalid. + * SHOULD BE STRICTLY AVOIDED. + */ + /* *(PULONG)(((PUCHAR)pvBuffer)+1)=psfLocalSet->u32SFID; */ + memcpy((((PUCHAR)pvBuffer)+1), &psfLocalSet->u32SFID, 4); + + if (pstAddIndication->sfActiveSet.bValid == TRUE) { + if (UPLINK_DIR == pstAddIndication->u8Direction) { + if (!Adapter->LinkUpStatus) { + netif_carrier_on(Adapter->dev); + netif_start_queue(Adapter->dev); + Adapter->LinkUpStatus = 1; + if (netif_msg_link(Adapter)) + pr_info(PFX "%s: link up\n", Adapter->dev->name); + atomic_set(&Adapter->TxPktAvail, 1); + wake_up(&Adapter->tx_packet_wait_queue); + Adapter->liTimeSinceLastNetEntry = get_seconds(); + } + } + } + } else { + Adapter->PackInfo[uiSearchRuleIndex].bActive = false; + Adapter->PackInfo[uiSearchRuleIndex].bValid = false; + Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value = 0; + kfree(pstAddIndication); + } + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "DSA ACK did not get valid SFID"); + kfree(pstAddIndication); + return false; + } + break; + case DSC_REQ: + pLeader->PLength = sizeof(struct bcm_change_indication); + pstChangeIndication = (struct bcm_change_indication *)pstAddIndication; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSC RESPONSE TO MAC %d", pLeader->PLength); + + *((struct bcm_change_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *pstChangeIndication; + ((struct bcm_change_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSC_RSP; + + CopyBufferToControlPacket(Adapter, (PVOID)Adapter->caDsxReqResp); + kfree(pstAddIndication); + break; + case DSC_RSP: + pLeader->PLength = sizeof(struct bcm_change_indication); + pstChangeIndication = (struct bcm_change_indication *)pstAddIndication; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSC ACK TO MAC %d", pLeader->PLength); + *((struct bcm_change_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *pstChangeIndication; + ((struct bcm_change_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSC_ACK; + /* FALLTHROUGH */ + case DSC_ACK: + pstChangeIndication = (struct bcm_change_indication *)pstAddIndication; + uiSearchRuleIndex = SearchSfid(Adapter, ntohl(pstChangeIndication->sfActiveSet.u32SFID)); + if (uiSearchRuleIndex > NO_OF_QUEUES-1) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "SF doesn't exist for which DSC_ACK is received"); + + if (uiSearchRuleIndex < NO_OF_QUEUES) { + Adapter->PackInfo[uiSearchRuleIndex].ucDirection = pstChangeIndication->u8Direction; + if (pstChangeIndication->sfActiveSet.bValid == TRUE) + Adapter->PackInfo[uiSearchRuleIndex].bActiveSet = TRUE; + + if (pstChangeIndication->sfAuthorizedSet.bValid == TRUE) + Adapter->PackInfo[uiSearchRuleIndex].bAuthorizedSet = TRUE; + + if (pstChangeIndication->sfAdmittedSet.bValid == TRUE) + Adapter->PackInfo[uiSearchRuleIndex].bAdmittedSet = TRUE; + + if (pstChangeIndication->sfActiveSet.bValid == false) { + Adapter->PackInfo[uiSearchRuleIndex].bActive = false; + Adapter->PackInfo[uiSearchRuleIndex].bActivateRequestSent = false; + + if (pstChangeIndication->sfAdmittedSet.bValid) + psfLocalSet = &pstChangeIndication->sfAdmittedSet; + else if (pstChangeIndication->sfAuthorizedSet.bValid) + psfLocalSet = &pstChangeIndication->sfAuthorizedSet; + } else { + psfLocalSet = &pstChangeIndication->sfActiveSet; + Adapter->PackInfo[uiSearchRuleIndex].bActive = TRUE; + } + + if (!psfLocalSet) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "No set is valid\n"); + Adapter->PackInfo[uiSearchRuleIndex].bActive = false; + Adapter->PackInfo[uiSearchRuleIndex].bValid = false; + Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value = 0; + kfree(pstAddIndication); + } else if (psfLocalSet->bValid && (pstChangeIndication->u8CC == 0)) { + Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value = ntohs(pstChangeIndication->u16VCID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "CC field is %d bvalid = %d\n", + pstChangeIndication->u8CC, psfLocalSet->bValid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "VCID= %d\n", ntohs(pstChangeIndication->u16VCID)); + Adapter->PackInfo[uiSearchRuleIndex].usCID = ntohs(pstChangeIndication->u16CID); + CopyToAdapter(Adapter, psfLocalSet, uiSearchRuleIndex, DSC_ACK, pstAddIndication); + + *(PULONG)(((PUCHAR)pvBuffer)+1) = psfLocalSet->u32SFID; + } else if (pstChangeIndication->u8CC == 6) { + deleteSFBySfid(Adapter, uiSearchRuleIndex); + kfree(pstAddIndication); + } + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "DSC ACK did not get valid SFID"); + kfree(pstAddIndication); + return false; + } + break; + case DSD_REQ: + pLeader->PLength = sizeof(struct bcm_del_indication); + *((struct bcm_del_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *((struct bcm_del_indication *)pstAddIndication); + + ulSFID = ntohl(((struct bcm_del_indication *)pstAddIndication)->u32SFID); + uiSearchRuleIndex = SearchSfid(Adapter, ulSFID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSD - Removing connection %x", uiSearchRuleIndex); + + if (uiSearchRuleIndex < NO_OF_QUEUES) { + /* Delete All Classifiers Associated with this SFID */ + deleteSFBySfid(Adapter, uiSearchRuleIndex); + Adapter->u32TotalDSD++; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSD RESPONSE TO MAC"); + ((struct bcm_del_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSD_RSP; + CopyBufferToControlPacket(Adapter, (PVOID)Adapter->caDsxReqResp); + /* FALLTHROUGH */ + case DSD_RSP: + /* Do nothing as SF has already got Deleted */ + break; + case DSD_ACK: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSD ACK Rcd, let App handle it\n"); + break; + default: + kfree(pstAddIndication); + return false; + } + return TRUE; +} + +int get_dsx_sf_data_to_application(struct bcm_mini_adapter *Adapter, + UINT uiSFId, void __user *user_buffer) +{ + int status = 0; + struct bcm_packet_info *psSfInfo = NULL; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "status =%d", status); + status = SearchSfid(Adapter, uiSFId); + if (status >= NO_OF_QUEUES) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "SFID %d not present in queue !!!", uiSFId); + return -EINVAL; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "status =%d", status); + psSfInfo = &Adapter->PackInfo[status]; + if (psSfInfo->pstSFIndication + && copy_to_user(user_buffer, psSfInfo->pstSFIndication, + sizeof(struct bcm_add_indication_alt))) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, + "copy to user failed SFID %d, present in queue !!!", + uiSFId); + status = -EFAULT; + return status; + } + return STATUS_SUCCESS; +} + +VOID OverrideServiceFlowParams(struct bcm_mini_adapter *Adapter, + PUINT puiBuffer) +{ + B_UINT32 u32NumofSFsinMsg = ntohl(*(puiBuffer + 1)); + struct bcm_stim_sfhostnotify *pHostInfo = NULL; + UINT uiSearchRuleIndex = 0; + ULONG ulSFID = 0; + + puiBuffer += 2; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "u32NumofSFsinMsg: 0x%x\n", u32NumofSFsinMsg); + + while (u32NumofSFsinMsg != 0 && u32NumofSFsinMsg < NO_OF_QUEUES) { + u32NumofSFsinMsg--; + pHostInfo = (struct bcm_stim_sfhostnotify *)puiBuffer; + puiBuffer = (PUINT)(pHostInfo + 1); + + ulSFID = ntohl(pHostInfo->SFID); + uiSearchRuleIndex = SearchSfid(Adapter, ulSFID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "SFID: 0x%lx\n", ulSFID); + + if (uiSearchRuleIndex >= NO_OF_QUEUES + || uiSearchRuleIndex == HiPriority) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, + DBG_LVL_ALL, + "The SFID <%lx> doesn't exist in host entry or is Invalid\n", + ulSFID); + continue; + } + + if (pHostInfo->RetainSF == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, + DBG_LVL_ALL, "Going to Delete SF"); + deleteSFBySfid(Adapter, uiSearchRuleIndex); + } else { + struct bcm_packet_info *packinfo = + &Adapter->PackInfo[uiSearchRuleIndex]; + + packinfo->usVCID_Value = ntohs(pHostInfo->VCID); + packinfo->usCID = ntohs(pHostInfo->newCID); + packinfo->bActive = false; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, + DBG_LVL_ALL, + "pHostInfo->QoSParamSet: 0x%x\n", + pHostInfo->QoSParamSet); + + if (pHostInfo->QoSParamSet & 0x1) + packinfo->bAuthorizedSet = TRUE; + if (pHostInfo->QoSParamSet & 0x2) + packinfo->bAdmittedSet = TRUE; + if (pHostInfo->QoSParamSet & 0x4) { + packinfo->bActiveSet = TRUE; + packinfo->bActive = TRUE; + } + } + } +} + +static void restore_endianess_of_pstClassifierEntry( + struct bcm_classifier_rule *pstClassifierEntry, + enum bcm_ipaddr_context eIpAddrContext) +{ + int i; + union u_ip_address *stSrc = &pstClassifierEntry->stSrcIpAddress; + union u_ip_address *stDest = &pstClassifierEntry->stDestIpAddress; + + for (i = 0; i < MAX_IP_RANGE_LENGTH * 4; i++) { + if (eIpAddrContext == eSrcIpAddress) { + stSrc->ulIpv6Addr[i] = ntohl(stSrc->ulIpv6Addr[i]); + stSrc->ulIpv6Mask[i] = ntohl(stSrc->ulIpv6Mask[i]); + } else if (eIpAddrContext == eDestIpAddress) { + stDest->ulIpv6Addr[i] = ntohl(stDest->ulIpv6Addr[i]); + stDest->ulIpv6Mask[i] = ntohl(stDest->ulIpv6Mask[i]); + } + } +} + +static void apply_phs_rule_to_all_classifiers( + register struct bcm_mini_adapter *Adapter, /* <Pointer to the Adapter structure */ + register UINT uiSearchRuleIndex, /* <Index of Queue, to which this data belongs */ + USHORT uVCID, + struct bcm_phs_rule *sPhsRule, + struct bcm_phs_rules *cPhsRule, + struct bcm_add_indication_alt *pstAddIndication) +{ + unsigned int uiClassifierIndex = 0; + struct bcm_classifier_rule *curr_classifier = NULL; + + if (pstAddIndication->u8Direction == UPLINK_DIR) { + for (uiClassifierIndex = 0; uiClassifierIndex < MAX_CLASSIFIERS; uiClassifierIndex++) { + curr_classifier = + &Adapter->astClassifierTable[uiClassifierIndex]; + if ((curr_classifier->bUsed) && + (curr_classifier->ulSFID == Adapter->PackInfo[uiSearchRuleIndex].ulSFID) && + (curr_classifier->u8AssociatedPHSI == cPhsRule->u8PHSI)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, + "Adding PHS Rule For Classifier: 0x%x cPhsRule.u8PHSI: 0x%x\n", + curr_classifier->uiClassifierRuleIndex, + cPhsRule->u8PHSI); + /* Update The PHS Rule for this classifier as Associated PHSI id defined */ + + /* Copy the PHS Rule */ + sPhsRule->u8PHSI = cPhsRule->u8PHSI; + sPhsRule->u8PHSFLength = cPhsRule->u8PHSFLength; + sPhsRule->u8PHSMLength = cPhsRule->u8PHSMLength; + sPhsRule->u8PHSS = cPhsRule->u8PHSS; + sPhsRule->u8PHSV = cPhsRule->u8PHSV; + memcpy(sPhsRule->u8PHSF, cPhsRule->u8PHSF, MAX_PHS_LENGTHS); + memcpy(sPhsRule->u8PHSM, cPhsRule->u8PHSM, MAX_PHS_LENGTHS); + sPhsRule->u8RefCnt = 0; + sPhsRule->bUnclassifiedPHSRule = false; + sPhsRule->PHSModifiedBytes = 0; + sPhsRule->PHSModifiedNumPackets = 0; + sPhsRule->PHSErrorNumPackets = 0; + + /* bPHSRuleAssociated = TRUE; */ + /* Store The PHS Rule for this classifier */ + + PhsUpdateClassifierRule( + &Adapter->stBCMPhsContext, + uVCID, + curr_classifier->uiClassifierRuleIndex, + sPhsRule, + curr_classifier->u8AssociatedPHSI); + + /* Update PHS Rule For the Classifier */ + if (sPhsRule->u8PHSI) { + curr_classifier->u32PHSRuleID = sPhsRule->u8PHSI; + memcpy(&curr_classifier->sPhsRule, sPhsRule, sizeof(struct bcm_phs_rule)); + } + } + } + } else { + /* Error PHS Rule specified in signaling could not be applied to any classifier */ + + /* Copy the PHS Rule */ + sPhsRule->u8PHSI = cPhsRule->u8PHSI; + sPhsRule->u8PHSFLength = cPhsRule->u8PHSFLength; + sPhsRule->u8PHSMLength = cPhsRule->u8PHSMLength; + sPhsRule->u8PHSS = cPhsRule->u8PHSS; + sPhsRule->u8PHSV = cPhsRule->u8PHSV; + memcpy(sPhsRule->u8PHSF, cPhsRule->u8PHSF, MAX_PHS_LENGTHS); + memcpy(sPhsRule->u8PHSM, cPhsRule->u8PHSM, MAX_PHS_LENGTHS); + sPhsRule->u8RefCnt = 0; + sPhsRule->bUnclassifiedPHSRule = TRUE; + sPhsRule->PHSModifiedBytes = 0; + sPhsRule->PHSModifiedNumPackets = 0; + sPhsRule->PHSErrorNumPackets = 0; + /* Store The PHS Rule for this classifier */ + + /* + * Passing the argument u8PHSI instead of clsid. Because for DL with no classifier rule, + * clsid will be zero hence we can't have multiple PHS rules for the same SF. + * To support multiple PHS rule, passing u8PHSI. + */ + PhsUpdateClassifierRule( + &Adapter->stBCMPhsContext, + uVCID, + sPhsRule->u8PHSI, + sPhsRule, + sPhsRule->u8PHSI); + } +} diff --git a/drivers/staging/bcm/CmHost.h b/drivers/staging/bcm/CmHost.h new file mode 100644 index 00000000000..0887d3f49e2 --- /dev/null +++ b/drivers/staging/bcm/CmHost.h @@ -0,0 +1,62 @@ +/*************************************************************************** + * (c) Beceem Communications Inc. + * All Rights Reserved + * + * file : CmHost.h + * author: Rajeev Tirumala + * date : September 8 , 2006 + * brief : Definitions for Connection Management Requests structure + * which we will use to setup our connection structures.Its high + * time we had a header file for CmHost.cpp to isolate the way + * f/w sends DSx messages and the way we interpret them in code. + * Revision History + * + * Date Author Version Description + * 08-Sep-06 Rajeev 0.1 Created + ***************************************************************************/ +#ifndef _CM_HOST_H +#define _CM_HOST_H + +#pragma once +#pragma pack(push, 4) + +#define DSX_MESSAGE_EXCHANGE_BUFFER 0xBF60AC84 /* This contains the pointer */ +#define DSX_MESSAGE_EXCHANGE_BUFFER_SIZE 72000 /* 24 K Bytes */ + +struct bcm_add_indication_alt { + u8 u8Type; + u8 u8Direction; + u16 u16TID; + u16 u16CID; + u16 u16VCID; + struct bcm_connect_mgr_params sfAuthorizedSet; + struct bcm_connect_mgr_params sfAdmittedSet; + struct bcm_connect_mgr_params sfActiveSet; + u8 u8CC; /* < Confirmation Code */ + u8 u8Padd; + u16 u16Padd; +}; + +struct bcm_change_indication { + u8 u8Type; + u8 u8Direction; + u16 u16TID; + u16 u16CID; + u16 u16VCID; + struct bcm_connect_mgr_params sfAuthorizedSet; + struct bcm_connect_mgr_params sfAdmittedSet; + struct bcm_connect_mgr_params sfActiveSet; + u8 u8CC; /* < Confirmation Code */ + u8 u8Padd; + u16 u16Padd; +}; + +unsigned long StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, void *pvBuffer, unsigned int *puBufferLength); +int AllocAdapterDsxBuffer(struct bcm_mini_adapter *Adapter); +int FreeAdapterDsxBuffer(struct bcm_mini_adapter *Adapter); +unsigned long SetUpTargetDsxBuffers(struct bcm_mini_adapter *Adapter); +bool CmControlResponseMessage(struct bcm_mini_adapter *Adapter, void *pvBuffer); + +#pragma pack(pop) + +#endif diff --git a/drivers/staging/bcm/DDRInit.c b/drivers/staging/bcm/DDRInit.c new file mode 100644 index 00000000000..f1d7cb82fd7 --- /dev/null +++ b/drivers/staging/bcm/DDRInit.c @@ -0,0 +1,1239 @@ +#include "headers.h" + + + +#define DDR_DUMP_INTERNAL_DEVICE_MEMORY 0xBFC02B00 +#define MIPS_CLOCK_REG 0x0f000820 + +/* DDR INIT-133Mhz */ +#define T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 12 /* index for 0x0F007000 */ +static struct bcm_ddr_setting asT3_DDRSetting133MHz[] = { /* DPLL Clock Setting */ + {0x0F000800, 0x00007212}, + {0x0f000820, 0x07F13FFF}, + {0x0f000810, 0x00000F95}, + {0x0f000860, 0x00000000}, + {0x0f000880, 0x000003DD}, + /* Changed source for X-bar and MIPS clock to APLL */ + {0x0f000840, 0x0FFF1B00}, + {0x0f000870, 0x00000002}, + {0x0F00a044, 0x1fffffff}, + {0x0F00a040, 0x1f000000}, + {0x0F00a084, 0x1Cffffff}, + {0x0F00a080, 0x1C000000}, + {0x0F00a04C, 0x0000000C}, + /* Memcontroller Default values */ + {0x0F007000, 0x00010001}, + {0x0F007004, 0x01010100}, + {0x0F007008, 0x01000001}, + {0x0F00700c, 0x00000000}, + {0x0F007010, 0x01000000}, + {0x0F007014, 0x01000100}, + {0x0F007018, 0x01000000}, + {0x0F00701c, 0x01020001}, + {0x0F007020, 0x04030107}, + {0x0F007024, 0x02000007}, + {0x0F007028, 0x02020202}, + {0x0F00702c, 0x0206060a}, + {0x0F007030, 0x05000000}, + {0x0F007034, 0x00000003}, + {0x0F007038, 0x110a0200}, + {0x0F00703C, 0x02101010}, + {0x0F007040, 0x45751200}, + {0x0F007044, 0x110a0d00}, + {0x0F007048, 0x081b0306}, + {0x0F00704c, 0x00000000}, + {0x0F007050, 0x0000001c}, + {0x0F007054, 0x00000000}, + {0x0F007058, 0x00000000}, + {0x0F00705c, 0x00000000}, + {0x0F007060, 0x0010246c}, + {0x0F007064, 0x00000010}, + {0x0F007068, 0x00000000}, + {0x0F00706c, 0x00000001}, + {0x0F007070, 0x00007000}, + {0x0F007074, 0x00000000}, + {0x0F007078, 0x00000000}, + {0x0F00707C, 0x00000000}, + {0x0F007080, 0x00000000}, + {0x0F007084, 0x00000000}, + /* Enable BW improvement within memory controller */ + {0x0F007094, 0x00000104}, + /* Enable 2 ports within X-bar */ + {0x0F00A000, 0x00000016}, + /* Enable start bit within memory controller */ + {0x0F007018, 0x01010000} +}; +/* 80Mhz */ +#define T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 10 /* index for 0x0F007000 */ +static struct bcm_ddr_setting asT3_DDRSetting80MHz[] = { /* DPLL Clock Setting */ + {0x0f000810, 0x00000F95}, + {0x0f000820, 0x07f1ffff}, + {0x0f000860, 0x00000000}, + {0x0f000880, 0x000003DD}, + {0x0F00a044, 0x1fffffff}, + {0x0F00a040, 0x1f000000}, + {0x0F00a084, 0x1Cffffff}, + {0x0F00a080, 0x1C000000}, + {0x0F00a000, 0x00000016}, + {0x0F00a04C, 0x0000000C}, + /* Memcontroller Default values */ + {0x0F007000, 0x00010001}, + {0x0F007004, 0x01000000}, + {0x0F007008, 0x01000001}, + {0x0F00700c, 0x00000000}, + {0x0F007010, 0x01000000}, + {0x0F007014, 0x01000100}, + {0x0F007018, 0x01000000}, + {0x0F00701c, 0x01020000}, + {0x0F007020, 0x04020107}, + {0x0F007024, 0x00000007}, + {0x0F007028, 0x02020201}, + {0x0F00702c, 0x0204040a}, + {0x0F007030, 0x04000000}, + {0x0F007034, 0x00000002}, + {0x0F007038, 0x1F060200}, + {0x0F00703C, 0x1C22221F}, + {0x0F007040, 0x8A006600}, + {0x0F007044, 0x221a0800}, + {0x0F007048, 0x02690204}, + {0x0F00704c, 0x00000000}, + {0x0F007050, 0x0000001c}, + {0x0F007054, 0x00000000}, + {0x0F007058, 0x00000000}, + {0x0F00705c, 0x00000000}, + {0x0F007060, 0x000A15D6}, + {0x0F007064, 0x0000000A}, + {0x0F007068, 0x00000000}, + {0x0F00706c, 0x00000001}, + {0x0F007070, 0x00004000}, + {0x0F007074, 0x00000000}, + {0x0F007078, 0x00000000}, + {0x0F00707C, 0x00000000}, + {0x0F007080, 0x00000000}, + {0x0F007084, 0x00000000}, + {0x0F007094, 0x00000104}, + /* Enable start bit within memory controller */ + {0x0F007018, 0x01010000} +}; +/* 100Mhz */ +#define T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 13 /* index for 0x0F007000 */ +static struct bcm_ddr_setting asT3_DDRSetting100MHz[] = { /* DPLL Clock Setting */ + {0x0F000800, 0x00007008}, + {0x0f000810, 0x00000F95}, + {0x0f000820, 0x07F13E3F}, + {0x0f000860, 0x00000000}, + {0x0f000880, 0x000003DD}, + /* Changed source for X-bar and MIPS clock to APLL */ + {0x0f000840, 0x0FFF1B00}, + {0x0f000870, 0x00000002}, + {0x0F00a044, 0x1fffffff}, + {0x0F00a040, 0x1f000000}, + {0x0F00a084, 0x1Cffffff}, + {0x0F00a080, 0x1C000000}, + {0x0F00a04C, 0x0000000C}, + /* Enable 2 ports within X-bar */ + {0x0F00A000, 0x00000016}, + /* Memcontroller Default values */ + {0x0F007000, 0x00010001}, + {0x0F007004, 0x01010100}, + {0x0F007008, 0x01000001}, + {0x0F00700c, 0x00000000}, + {0x0F007010, 0x01000000}, + {0x0F007014, 0x01000100}, + {0x0F007018, 0x01000000}, + {0x0F00701c, 0x01020001}, + {0x0F007020, 0x04020107}, + {0x0F007024, 0x00000007}, + {0x0F007028, 0x01020201}, + {0x0F00702c, 0x0204040A}, + {0x0F007030, 0x06000000}, + {0x0F007034, 0x00000004}, + {0x0F007038, 0x20080200}, + {0x0F00703C, 0x02030320}, + {0x0F007040, 0x6E7F1200}, + {0x0F007044, 0x01190A00}, + {0x0F007048, 0x06120305}, + {0x0F00704c, 0x00000000}, + {0x0F007050, 0x0000001C}, + {0x0F007054, 0x00000000}, + {0x0F007058, 0x00000000}, + {0x0F00705c, 0x00000000}, + {0x0F007060, 0x00082ED6}, + {0x0F007064, 0x0000000A}, + {0x0F007068, 0x00000000}, + {0x0F00706c, 0x00000001}, + {0x0F007070, 0x00005000}, + {0x0F007074, 0x00000000}, + {0x0F007078, 0x00000000}, + {0x0F00707C, 0x00000000}, + {0x0F007080, 0x00000000}, + {0x0F007084, 0x00000000}, + /* Enable BW improvement within memory controller */ + {0x0F007094, 0x00000104}, + /* Enable start bit within memory controller */ + {0x0F007018, 0x01010000} +}; + +/* Net T3B DDR Settings + * DDR INIT-133Mhz + */ +static struct bcm_ddr_setting asDPLL_266MHZ[] = { + {0x0F000800, 0x00007212}, + {0x0f000820, 0x07F13FFF}, + {0x0f000810, 0x00000F95}, + {0x0f000860, 0x00000000}, + {0x0f000880, 0x000003DD}, + /* Changed source for X-bar and MIPS clock to APLL */ + {0x0f000840, 0x0FFF1B00}, + {0x0f000870, 0x00000002} +}; + +#define T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 11 /* index for 0x0F007000 */ +static struct bcm_ddr_setting asT3B_DDRSetting133MHz[] = { /* DPLL Clock Setting */ + {0x0f000810, 0x00000F95}, + {0x0f000810, 0x00000F95}, + {0x0f000810, 0x00000F95}, + {0x0f000820, 0x07F13652}, + {0x0f000840, 0x0FFF0800}, + /* Changed source for X-bar and MIPS clock to APLL */ + {0x0f000880, 0x000003DD}, + {0x0f000860, 0x00000000}, + /* Changed source for X-bar and MIPS clock to APLL */ + {0x0F00a044, 0x1fffffff}, + {0x0F00a040, 0x1f000000}, + {0x0F00a084, 0x1Cffffff}, + {0x0F00a080, 0x1C000000}, + /* Enable 2 ports within X-bar */ + {0x0F00A000, 0x00000016}, + /* Memcontroller Default values */ + {0x0F007000, 0x00010001}, + {0x0F007004, 0x01010100}, + {0x0F007008, 0x01000001}, + {0x0F00700c, 0x00000000}, + {0x0F007010, 0x01000000}, + {0x0F007014, 0x01000100}, + {0x0F007018, 0x01000000}, + {0x0F00701c, 0x01020001}, + {0x0F007020, 0x04030107}, + {0x0F007024, 0x02000007}, + {0x0F007028, 0x02020202}, + {0x0F00702c, 0x0206060a}, + {0x0F007030, 0x05000000}, + {0x0F007034, 0x00000003}, + {0x0F007038, 0x130a0200}, + {0x0F00703C, 0x02101012}, + {0x0F007040, 0x457D1200}, + {0x0F007044, 0x11130d00}, + {0x0F007048, 0x040D0306}, + {0x0F00704c, 0x00000000}, + {0x0F007050, 0x0000001c}, + {0x0F007054, 0x00000000}, + {0x0F007058, 0x00000000}, + {0x0F00705c, 0x00000000}, + {0x0F007060, 0x0010246c}, + {0x0F007064, 0x00000012}, + {0x0F007068, 0x00000000}, + {0x0F00706c, 0x00000001}, + {0x0F007070, 0x00007000}, + {0x0F007074, 0x00000000}, + {0x0F007078, 0x00000000}, + {0x0F00707C, 0x00000000}, + {0x0F007080, 0x00000000}, + {0x0F007084, 0x00000000}, + /* Enable BW improvement within memory controller */ + {0x0F007094, 0x00000104}, + /* Enable start bit within memory controller */ + {0x0F007018, 0x01010000}, + }; + +#define T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 9 /* index for 0x0F007000 */ +static struct bcm_ddr_setting asT3B_DDRSetting80MHz[] = { /* DPLL Clock Setting */ + {0x0f000810, 0x00000F95}, + {0x0f000820, 0x07F13FFF}, + {0x0f000840, 0x0FFF1F00}, + {0x0f000880, 0x000003DD}, + {0x0f000860, 0x00000000}, + + {0x0F00a044, 0x1fffffff}, + {0x0F00a040, 0x1f000000}, + {0x0F00a084, 0x1Cffffff}, + {0x0F00a080, 0x1C000000}, + {0x0F00a000, 0x00000016}, + /* Memcontroller Default values */ + {0x0F007000, 0x00010001}, + {0x0F007004, 0x01000000}, + {0x0F007008, 0x01000001}, + {0x0F00700c, 0x00000000}, + {0x0F007010, 0x01000000}, + {0x0F007014, 0x01000100}, + {0x0F007018, 0x01000000}, + {0x0F00701c, 0x01020000}, + {0x0F007020, 0x04020107}, + {0x0F007024, 0x00000007}, + {0x0F007028, 0x02020201}, + {0x0F00702c, 0x0204040a}, + {0x0F007030, 0x04000000}, + {0x0F007034, 0x02000002}, + {0x0F007038, 0x1F060202}, + {0x0F00703C, 0x1C22221F}, + {0x0F007040, 0x8A006600}, + {0x0F007044, 0x221a0800}, + {0x0F007048, 0x02690204}, + {0x0F00704c, 0x00000000}, + {0x0F007050, 0x0100001c}, + {0x0F007054, 0x00000000}, + {0x0F007058, 0x00000000}, + {0x0F00705c, 0x00000000}, + {0x0F007060, 0x000A15D6}, + {0x0F007064, 0x0000000A}, + {0x0F007068, 0x00000000}, + {0x0F00706c, 0x00000001}, + {0x0F007070, 0x00004000}, + {0x0F007074, 0x00000000}, + {0x0F007078, 0x00000000}, + {0x0F00707C, 0x00000000}, + {0x0F007080, 0x00000000}, + {0x0F007084, 0x00000000}, + {0x0F007094, 0x00000104}, + /* Enable start bit within memory controller */ + {0x0F007018, 0x01010000} +}; + +/* 100Mhz */ +#define T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 9 /* index for 0x0F007000 */ +static struct bcm_ddr_setting asT3B_DDRSetting100MHz[] = { /* DPLL Clock Setting */ + {0x0f000810, 0x00000F95}, + {0x0f000820, 0x07F1369B}, + {0x0f000840, 0x0FFF0800}, + {0x0f000880, 0x000003DD}, + {0x0f000860, 0x00000000}, + {0x0F00a044, 0x1fffffff}, + {0x0F00a040, 0x1f000000}, + {0x0F00a084, 0x1Cffffff}, + {0x0F00a080, 0x1C000000}, + /* Enable 2 ports within X-bar */ + {0x0F00A000, 0x00000016}, + /* Memcontroller Default values */ + {0x0F007000, 0x00010001}, + {0x0F007004, 0x01010100}, + {0x0F007008, 0x01000001}, + {0x0F00700c, 0x00000000}, + {0x0F007010, 0x01000000}, + {0x0F007014, 0x01000100}, + {0x0F007018, 0x01000000}, + {0x0F00701c, 0x01020000}, + {0x0F007020, 0x04020107}, + {0x0F007024, 0x00000007}, + {0x0F007028, 0x01020201}, + {0x0F00702c, 0x0204040A}, + {0x0F007030, 0x06000000}, + {0x0F007034, 0x02000004}, + {0x0F007038, 0x20080200}, + {0x0F00703C, 0x02030320}, + {0x0F007040, 0x6E7F1200}, + {0x0F007044, 0x01190A00}, + {0x0F007048, 0x06120305}, + {0x0F00704c, 0x00000000}, + {0x0F007050, 0x0100001C}, + {0x0F007054, 0x00000000}, + {0x0F007058, 0x00000000}, + {0x0F00705c, 0x00000000}, + {0x0F007060, 0x00082ED6}, + {0x0F007064, 0x0000000A}, + {0x0F007068, 0x00000000}, + {0x0F00706c, 0x00000001}, + {0x0F007070, 0x00005000}, + {0x0F007074, 0x00000000}, + {0x0F007078, 0x00000000}, + {0x0F00707C, 0x00000000}, + {0x0F007080, 0x00000000}, + {0x0F007084, 0x00000000}, + /* Enable BW improvement within memory controller */ + {0x0F007094, 0x00000104}, + /* Enable start bit within memory controller */ + {0x0F007018, 0x01010000} +}; + + +#define T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 9 /* index for 0x0F007000 */ +static struct bcm_ddr_setting asT3LP_DDRSetting133MHz[] = { /* DPLL Clock Setting */ + {0x0f000820, 0x03F1365B}, + {0x0f000810, 0x00002F95}, + {0x0f000880, 0x000003DD}, + /* Changed source for X-bar and MIPS clock to APLL */ + {0x0f000840, 0x0FFF0000}, + {0x0f000860, 0x00000000}, + {0x0F00a044, 0x1fffffff}, + {0x0F00a040, 0x1f000000}, + {0x0F00a084, 0x1Cffffff}, + {0x0F00a080, 0x1C000000}, + {0x0F00A000, 0x00000016}, + /* Memcontroller Default values */ + {0x0F007000, 0x00010001}, + {0x0F007004, 0x01010100}, + {0x0F007008, 0x01000001}, + {0x0F00700c, 0x00000000}, + {0x0F007010, 0x01000000}, + {0x0F007014, 0x01000100}, + {0x0F007018, 0x01000000}, + {0x0F00701c, 0x01020001}, + {0x0F007020, 0x04030107}, + {0x0F007024, 0x02000007}, + {0x0F007028, 0x02020200}, + {0x0F00702c, 0x0206060a}, + {0x0F007030, 0x05000000}, + {0x0F007034, 0x00000003}, + {0x0F007038, 0x200a0200}, + {0x0F00703C, 0x02101020}, + {0x0F007040, 0x45711200}, + {0x0F007044, 0x110D0D00}, + {0x0F007048, 0x04080306}, + {0x0F00704c, 0x00000000}, + {0x0F007050, 0x0100001c}, + {0x0F007054, 0x00000000}, + {0x0F007058, 0x00000000}, + {0x0F00705c, 0x00000000}, + {0x0F007060, 0x0010245F}, + {0x0F007064, 0x00000010}, + {0x0F007068, 0x00000000}, + {0x0F00706c, 0x00000001}, + {0x0F007070, 0x00007000}, + {0x0F007074, 0x00000000}, + {0x0F007078, 0x00000000}, + {0x0F00707C, 0x00000000}, + {0x0F007080, 0x00000000}, + {0x0F007084, 0x00000000}, + {0x0F007088, 0x01000001}, + {0x0F00708c, 0x00000101}, + {0x0F007090, 0x00000000}, + /* Enable BW improvement within memory controller */ + {0x0F007094, 0x00040000}, + {0x0F007098, 0x00000000}, + {0x0F0070c8, 0x00000104}, + /* Enable 2 ports within X-bar */ + /* Enable start bit within memory controller */ + {0x0F007018, 0x01010000} +}; + +#define T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 11 /* index for 0x0F007000 */ +static struct bcm_ddr_setting asT3LP_DDRSetting100MHz[] = { /* DPLL Clock Setting */ + {0x0f000810, 0x00002F95}, + {0x0f000820, 0x03F1369B}, + {0x0f000840, 0x0fff0000}, + {0x0f000860, 0x00000000}, + {0x0f000880, 0x000003DD}, + /* Changed source for X-bar and MIPS clock to APLL */ + {0x0f000840, 0x0FFF0000}, + {0x0F00a044, 0x1fffffff}, + {0x0F00a040, 0x1f000000}, + {0x0F00a084, 0x1Cffffff}, + {0x0F00a080, 0x1C000000}, + /* Memcontroller Default values */ + {0x0F007000, 0x00010001}, + {0x0F007004, 0x01010100}, + {0x0F007008, 0x01000001}, + {0x0F00700c, 0x00000000}, + {0x0F007010, 0x01000000}, + {0x0F007014, 0x01000100}, + {0x0F007018, 0x01000000}, + {0x0F00701c, 0x01020000}, + {0x0F007020, 0x04020107}, + {0x0F007024, 0x00000007}, + {0x0F007028, 0x01020200}, + {0x0F00702c, 0x0204040a}, + {0x0F007030, 0x06000000}, + {0x0F007034, 0x00000004}, + {0x0F007038, 0x1F080200}, + {0x0F00703C, 0x0203031F}, + {0x0F007040, 0x6e001200}, + {0x0F007044, 0x011a0a00}, + {0x0F007048, 0x03000305}, + {0x0F00704c, 0x00000000}, + {0x0F007050, 0x0100001c}, + {0x0F007054, 0x00000000}, + {0x0F007058, 0x00000000}, + {0x0F00705c, 0x00000000}, + {0x0F007060, 0x00082ED6}, + {0x0F007064, 0x0000000A}, + {0x0F007068, 0x00000000}, + {0x0F00706c, 0x00000001}, + {0x0F007070, 0x00005000}, + {0x0F007074, 0x00000000}, + {0x0F007078, 0x00000000}, + {0x0F00707C, 0x00000000}, + {0x0F007080, 0x00000000}, + {0x0F007084, 0x00000000}, + {0x0F007088, 0x01000001}, + {0x0F00708c, 0x00000101}, + {0x0F007090, 0x00000000}, + {0x0F007094, 0x00010000}, + {0x0F007098, 0x00000000}, + {0x0F0070C8, 0x00000104}, + /* Enable 2 ports within X-bar */ + {0x0F00A000, 0x00000016}, + /* Enable start bit within memory controller */ + {0x0F007018, 0x01010000} +}; + +#define T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 9 /* index for 0x0F007000 */ +static struct bcm_ddr_setting asT3LP_DDRSetting80MHz[] = { /* DPLL Clock Setting */ + {0x0f000820, 0x07F13FFF}, + {0x0f000810, 0x00002F95}, + {0x0f000860, 0x00000000}, + {0x0f000880, 0x000003DD}, + {0x0f000840, 0x0FFF1F00}, + {0x0F00a044, 0x1fffffff}, + {0x0F00a040, 0x1f000000}, + {0x0F00a084, 0x1Cffffff}, + {0x0F00a080, 0x1C000000}, + {0x0F00A000, 0x00000016}, + {0x0f007000, 0x00010001}, + {0x0f007004, 0x01000000}, + {0x0f007008, 0x01000001}, + {0x0f00700c, 0x00000000}, + {0x0f007010, 0x01000000}, + {0x0f007014, 0x01000100}, + {0x0f007018, 0x01000000}, + {0x0f00701c, 0x01020000}, + {0x0f007020, 0x04020107}, + {0x0f007024, 0x00000007}, + {0x0f007028, 0x02020200}, + {0x0f00702c, 0x0204040a}, + {0x0f007030, 0x04000000}, + {0x0f007034, 0x00000002}, + {0x0f007038, 0x1d060200}, + {0x0f00703c, 0x1c22221d}, + {0x0f007040, 0x8A116600}, + {0x0f007044, 0x222d0800}, + {0x0f007048, 0x02690204}, + {0x0f00704c, 0x00000000}, + {0x0f007050, 0x0100001c}, + {0x0f007054, 0x00000000}, + {0x0f007058, 0x00000000}, + {0x0f00705c, 0x00000000}, + {0x0f007060, 0x000A15D6}, + {0x0f007064, 0x0000000A}, + {0x0f007068, 0x00000000}, + {0x0f00706c, 0x00000001}, + {0x0f007070, 0x00004000}, + {0x0f007074, 0x00000000}, + {0x0f007078, 0x00000000}, + {0x0f00707c, 0x00000000}, + {0x0f007080, 0x00000000}, + {0x0f007084, 0x00000000}, + {0x0f007088, 0x01000001}, + {0x0f00708c, 0x00000101}, + {0x0f007090, 0x00000000}, + {0x0f007094, 0x00010000}, + {0x0f007098, 0x00000000}, + {0x0F0070C8, 0x00000104}, + {0x0F007018, 0x01010000} +}; + + + + +/* T3 LP-B (UMA-B) */ + +#define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ 7 /* index for 0x0F007000 */ +static struct bcm_ddr_setting asT3LPB_DDRSetting160MHz[] = { /* DPLL Clock Setting */ + {0x0f000820, 0x03F137DB}, + {0x0f000810, 0x01842795}, + {0x0f000860, 0x00000000}, + {0x0f000880, 0x000003DD}, + {0x0f000840, 0x0FFF0400}, + {0x0F00a044, 0x1fffffff}, + {0x0F00a040, 0x1f000000}, + {0x0f003050, 0x00000021}, /* this is flash/eeprom clock divisor which set the flash clock to 20 MHz */ + {0x0F00a084, 0x1Cffffff}, /* Now dump from her in internal memory */ + {0x0F00a080, 0x1C000000}, + {0x0F00A000, 0x00000016}, + {0x0f007000, 0x00010001}, + {0x0f007004, 0x01000001}, + {0x0f007008, 0x01000101}, + {0x0f00700c, 0x00000000}, + {0x0f007010, 0x01000100}, + {0x0f007014, 0x01000100}, + {0x0f007018, 0x01000000}, + {0x0f00701c, 0x01020000}, + {0x0f007020, 0x04030107}, + {0x0f007024, 0x02000007}, + {0x0f007028, 0x02020200}, + {0x0f00702c, 0x0206060a}, + {0x0f007030, 0x050d0d00}, + {0x0f007034, 0x00000003}, + {0x0f007038, 0x170a0200}, + {0x0f00703c, 0x02101012}, + {0x0f007040, 0x45161200}, + {0x0f007044, 0x11250c00}, + {0x0f007048, 0x04da0307}, + {0x0f00704c, 0x00000000}, + {0x0f007050, 0x0000001c}, + {0x0f007054, 0x00000000}, + {0x0f007058, 0x00000000}, + {0x0f00705c, 0x00000000}, + {0x0f007060, 0x00142bb6}, + {0x0f007064, 0x20430014}, + {0x0f007068, 0x00000000}, + {0x0f00706c, 0x00000001}, + {0x0f007070, 0x00009000}, + {0x0f007074, 0x00000000}, + {0x0f007078, 0x00000000}, + {0x0f00707c, 0x00000000}, + {0x0f007080, 0x00000000}, + {0x0f007084, 0x00000000}, + {0x0f007088, 0x01000001}, + {0x0f00708c, 0x00000101}, + {0x0f007090, 0x00000000}, + {0x0f007094, 0x00040000}, + {0x0f007098, 0x00000000}, + {0x0F0070C8, 0x00000104}, + {0x0F007018, 0x01010000} +}; + + +#define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ 7 /* index for 0x0F007000 */ +static struct bcm_ddr_setting asT3LPB_DDRSetting133MHz[] = { /* DPLL Clock Setting */ + {0x0f000820, 0x03F1365B}, + {0x0f000810, 0x00002F95}, + {0x0f000880, 0x000003DD}, + /* Changed source for X-bar and MIPS clock to APLL */ + {0x0f000840, 0x0FFF0000}, + {0x0f000860, 0x00000000}, + {0x0F00a044, 0x1fffffff}, + {0x0F00a040, 0x1f000000}, + {0x0f003050, 0x00000021}, /* flash/eeprom clock divisor which set the flash clock to 20 MHz */ + {0x0F00a084, 0x1Cffffff}, /* dump from here in internal memory */ + {0x0F00a080, 0x1C000000}, + {0x0F00A000, 0x00000016}, + /* Memcontroller Default values */ + {0x0F007000, 0x00010001}, + {0x0F007004, 0x01010100}, + {0x0F007008, 0x01000001}, + {0x0F00700c, 0x00000000}, + {0x0F007010, 0x01000000}, + {0x0F007014, 0x01000100}, + {0x0F007018, 0x01000000}, + {0x0F00701c, 0x01020001}, + {0x0F007020, 0x04030107}, + {0x0F007024, 0x02000007}, + {0x0F007028, 0x02020200}, + {0x0F00702c, 0x0206060a}, + {0x0F007030, 0x05000000}, + {0x0F007034, 0x00000003}, + {0x0F007038, 0x190a0200}, + {0x0F00703C, 0x02101017}, + {0x0F007040, 0x45171200}, + {0x0F007044, 0x11290D00}, + {0x0F007048, 0x04080306}, + {0x0F00704c, 0x00000000}, + {0x0F007050, 0x0100001c}, + {0x0F007054, 0x00000000}, + {0x0F007058, 0x00000000}, + {0x0F00705c, 0x00000000}, + {0x0F007060, 0x0010245F}, + {0x0F007064, 0x00000010}, + {0x0F007068, 0x00000000}, + {0x0F00706c, 0x00000001}, + {0x0F007070, 0x00007000}, + {0x0F007074, 0x00000000}, + {0x0F007078, 0x00000000}, + {0x0F00707C, 0x00000000}, + {0x0F007080, 0x00000000}, + {0x0F007084, 0x00000000}, + {0x0F007088, 0x01000001}, + {0x0F00708c, 0x00000101}, + {0x0F007090, 0x00000000}, + /* Enable BW improvement within memory controller */ + {0x0F007094, 0x00040000}, + {0x0F007098, 0x00000000}, + {0x0F0070c8, 0x00000104}, + /* Enable 2 ports within X-bar */ + /* Enable start bit within memory controller */ + {0x0F007018, 0x01010000} +}; + +#define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ 8 /* index for 0x0F007000 */ +static struct bcm_ddr_setting asT3LPB_DDRSetting100MHz[] = { /* DPLL Clock Setting */ + {0x0f000810, 0x00002F95}, + {0x0f000820, 0x03F1369B}, + {0x0f000840, 0x0fff0000}, + {0x0f000860, 0x00000000}, + {0x0f000880, 0x000003DD}, + /* Changed source for X-bar and MIPS clock to APLL */ + {0x0f000840, 0x0FFF0000}, + {0x0F00a044, 0x1fffffff}, + {0x0F00a040, 0x1f000000}, + {0x0f003050, 0x00000021}, /* flash/eeprom clock divisor which set the flash clock to 20 MHz */ + {0x0F00a084, 0x1Cffffff}, /* dump from here in internal memory */ + {0x0F00a080, 0x1C000000}, + /* Memcontroller Default values */ + {0x0F007000, 0x00010001}, + {0x0F007004, 0x01010100}, + {0x0F007008, 0x01000001}, + {0x0F00700c, 0x00000000}, + {0x0F007010, 0x01000000}, + {0x0F007014, 0x01000100}, + {0x0F007018, 0x01000000}, + {0x0F00701c, 0x01020000}, + {0x0F007020, 0x04020107}, + {0x0F007024, 0x00000007}, + {0x0F007028, 0x01020200}, + {0x0F00702c, 0x0204040a}, + {0x0F007030, 0x06000000}, + {0x0F007034, 0x00000004}, + {0x0F007038, 0x1F080200}, + {0x0F00703C, 0x0203031F}, + {0x0F007040, 0x6e001200}, + {0x0F007044, 0x011a0a00}, + {0x0F007048, 0x03000305}, + {0x0F00704c, 0x00000000}, + {0x0F007050, 0x0100001c}, + {0x0F007054, 0x00000000}, + {0x0F007058, 0x00000000}, + {0x0F00705c, 0x00000000}, + {0x0F007060, 0x00082ED6}, + {0x0F007064, 0x0000000A}, + {0x0F007068, 0x00000000}, + {0x0F00706c, 0x00000001}, + {0x0F007070, 0x00005000}, + {0x0F007074, 0x00000000}, + {0x0F007078, 0x00000000}, + {0x0F00707C, 0x00000000}, + {0x0F007080, 0x00000000}, + {0x0F007084, 0x00000000}, + {0x0F007088, 0x01000001}, + {0x0F00708c, 0x00000101}, + {0x0F007090, 0x00000000}, + {0x0F007094, 0x00010000}, + {0x0F007098, 0x00000000}, + {0x0F0070C8, 0x00000104}, + /* Enable 2 ports within X-bar */ + {0x0F00A000, 0x00000016}, + /* Enable start bit within memory controller */ + {0x0F007018, 0x01010000} +}; + +#define T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ 7 /* index for 0x0F007000 */ +static struct bcm_ddr_setting asT3LPB_DDRSetting80MHz[] = { /* DPLL Clock Setting */ + {0x0f000820, 0x07F13FFF}, + {0x0f000810, 0x00002F95}, + {0x0f000860, 0x00000000}, + {0x0f000880, 0x000003DD}, + {0x0f000840, 0x0FFF1F00}, + {0x0F00a044, 0x1fffffff}, + {0x0F00a040, 0x1f000000}, + {0x0f003050, 0x00000021}, /* flash/eeprom clock divisor which set the flash clock to 20 MHz */ + {0x0F00a084, 0x1Cffffff}, /* dump from here in internal memory */ + {0x0F00a080, 0x1C000000}, + {0x0F00A000, 0x00000016}, + {0x0f007000, 0x00010001}, + {0x0f007004, 0x01000000}, + {0x0f007008, 0x01000001}, + {0x0f00700c, 0x00000000}, + {0x0f007010, 0x01000000}, + {0x0f007014, 0x01000100}, + {0x0f007018, 0x01000000}, + {0x0f00701c, 0x01020000}, + {0x0f007020, 0x04020107}, + {0x0f007024, 0x00000007}, + {0x0f007028, 0x02020200}, + {0x0f00702c, 0x0204040a}, + {0x0f007030, 0x04000000}, + {0x0f007034, 0x00000002}, + {0x0f007038, 0x1d060200}, + {0x0f00703c, 0x1c22221d}, + {0x0f007040, 0x8A116600}, + {0x0f007044, 0x222d0800}, + {0x0f007048, 0x02690204}, + {0x0f00704c, 0x00000000}, + {0x0f007050, 0x0100001c}, + {0x0f007054, 0x00000000}, + {0x0f007058, 0x00000000}, + {0x0f00705c, 0x00000000}, + {0x0f007060, 0x000A15D6}, + {0x0f007064, 0x0000000A}, + {0x0f007068, 0x00000000}, + {0x0f00706c, 0x00000001}, + {0x0f007070, 0x00004000}, + {0x0f007074, 0x00000000}, + {0x0f007078, 0x00000000}, + {0x0f00707c, 0x00000000}, + {0x0f007080, 0x00000000}, + {0x0f007084, 0x00000000}, + {0x0f007088, 0x01000001}, + {0x0f00708c, 0x00000101}, + {0x0f007090, 0x00000000}, + {0x0f007094, 0x00010000}, + {0x0f007098, 0x00000000}, + {0x0F0070C8, 0x00000104}, + {0x0F007018, 0x01010000} +}; + + +int ddr_init(struct bcm_mini_adapter *Adapter) +{ + struct bcm_ddr_setting *psDDRSetting = NULL; + ULONG RegCount = 0; + UINT value = 0; + UINT uiResetValue = 0; + UINT uiClockSetting = 0; + int retval = STATUS_SUCCESS; + + switch (Adapter->chip_id) { + case 0xbece3200: + switch (Adapter->DDRSetting) { + case DDR_80_MHZ: + psDDRSetting = asT3LP_DDRSetting80MHz; + RegCount = (sizeof(asT3LP_DDRSetting80MHz)/ + sizeof(struct bcm_ddr_setting)); + break; + case DDR_100_MHZ: + psDDRSetting = asT3LP_DDRSetting100MHz; + RegCount = (sizeof(asT3LP_DDRSetting100MHz)/ + sizeof(struct bcm_ddr_setting)); + break; + case DDR_133_MHZ: + psDDRSetting = asT3LP_DDRSetting133MHz; + RegCount = (sizeof(asT3LP_DDRSetting133MHz)/ + sizeof(struct bcm_ddr_setting)); + if (Adapter->bMipsConfig == MIPS_200_MHZ) + uiClockSetting = 0x03F13652; + else + uiClockSetting = 0x03F1365B; + break; + default: + return -EINVAL; + } + + break; + case T3LPB: + case BCS220_2: + case BCS220_2BC: + case BCS250_BC: + case BCS220_3: + /* Set bit 2 and bit 6 to 1 for BBIC 2mA drive + * (please check current value and additionally set these bits) + */ + if ((Adapter->chip_id != BCS220_2) && + (Adapter->chip_id != BCS220_2BC) && + (Adapter->chip_id != BCS220_3)) { + retval = rdmalt(Adapter, (UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + uiResetValue |= 0x44; + retval = wrmalt(Adapter, (UINT)0x0f000830, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + } + switch (Adapter->DDRSetting) { + + + + case DDR_80_MHZ: + psDDRSetting = asT3LPB_DDRSetting80MHz; + RegCount = (sizeof(asT3B_DDRSetting80MHz)/ + sizeof(struct bcm_ddr_setting)); + break; + case DDR_100_MHZ: + psDDRSetting = asT3LPB_DDRSetting100MHz; + RegCount = (sizeof(asT3B_DDRSetting100MHz)/ + sizeof(struct bcm_ddr_setting)); + break; + case DDR_133_MHZ: + psDDRSetting = asT3LPB_DDRSetting133MHz; + RegCount = (sizeof(asT3B_DDRSetting133MHz)/ + sizeof(struct bcm_ddr_setting)); + + if (Adapter->bMipsConfig == MIPS_200_MHZ) + uiClockSetting = 0x03F13652; + else + uiClockSetting = 0x03F1365B; + break; + + case DDR_160_MHZ: + psDDRSetting = asT3LPB_DDRSetting160MHz; + RegCount = sizeof(asT3LPB_DDRSetting160MHz)/sizeof(struct bcm_ddr_setting); + + if (Adapter->bMipsConfig == MIPS_200_MHZ) + uiClockSetting = 0x03F137D2; + else + uiClockSetting = 0x03F137DB; + } + break; + + case 0xbece0110: + case 0xbece0120: + case 0xbece0121: + case 0xbece0130: + case 0xbece0300: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "DDR Setting: %x\n", Adapter->DDRSetting); + switch (Adapter->DDRSetting) { + case DDR_80_MHZ: + psDDRSetting = asT3_DDRSetting80MHz; + RegCount = (sizeof(asT3_DDRSetting80MHz)/ + sizeof(struct bcm_ddr_setting)); + break; + case DDR_100_MHZ: + psDDRSetting = asT3_DDRSetting100MHz; + RegCount = (sizeof(asT3_DDRSetting100MHz)/ + sizeof(struct bcm_ddr_setting)); + break; + case DDR_133_MHZ: + psDDRSetting = asT3_DDRSetting133MHz; + RegCount = (sizeof(asT3_DDRSetting133MHz)/ + sizeof(struct bcm_ddr_setting)); + break; + default: + return -EINVAL; + } + case 0xbece0310: + { + switch (Adapter->DDRSetting) { + case DDR_80_MHZ: + psDDRSetting = asT3B_DDRSetting80MHz; + RegCount = (sizeof(asT3B_DDRSetting80MHz)/ + sizeof(struct bcm_ddr_setting)); + break; + case DDR_100_MHZ: + psDDRSetting = asT3B_DDRSetting100MHz; + RegCount = (sizeof(asT3B_DDRSetting100MHz)/ + sizeof(struct bcm_ddr_setting)); + break; + case DDR_133_MHZ: + + if (Adapter->bDPLLConfig == PLL_266_MHZ) { /* 266Mhz PLL selected. */ + memcpy(asT3B_DDRSetting133MHz, asDPLL_266MHZ, + sizeof(asDPLL_266MHZ)); + psDDRSetting = asT3B_DDRSetting133MHz; + RegCount = (sizeof(asT3B_DDRSetting133MHz)/ + sizeof(struct bcm_ddr_setting)); + } else { + psDDRSetting = asT3B_DDRSetting133MHz; + RegCount = (sizeof(asT3B_DDRSetting133MHz)/ + sizeof(struct bcm_ddr_setting)); + if (Adapter->bMipsConfig == MIPS_200_MHZ) + uiClockSetting = 0x07F13652; + else + uiClockSetting = 0x07F1365B; + } + break; + default: + return -EINVAL; + } + break; + + } + default: + return -EINVAL; + } + + value = 0; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, "Register Count is =%lu\n", RegCount); + while (RegCount && !retval) { + if (uiClockSetting && psDDRSetting->ulRegAddress == MIPS_CLOCK_REG) + value = uiClockSetting; + else + value = psDDRSetting->ulRegValue; + retval = wrmalt(Adapter, psDDRSetting->ulRegAddress, &value, sizeof(value)); + if (STATUS_SUCCESS != retval) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__); + break; + } + + RegCount--; + psDDRSetting++; + } + + if (Adapter->chip_id >= 0xbece3300) { + + mdelay(3); + if ((Adapter->chip_id != BCS220_2) && + (Adapter->chip_id != BCS220_2BC) && + (Adapter->chip_id != BCS220_3)) { + /* drive MDDR to half in case of UMA-B: */ + uiResetValue = 0x01010001; + retval = wrmalt(Adapter, (UINT)0x0F007018, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + uiResetValue = 0x00040020; + retval = wrmalt(Adapter, (UINT)0x0F007094, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + uiResetValue = 0x01020101; + retval = wrmalt(Adapter, (UINT)0x0F00701c, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + uiResetValue = 0x01010000; + retval = wrmalt(Adapter, (UINT)0x0F007018, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + } + mdelay(3); + + /* DC/DC standby change... + * This is to be done only for Hybrid PMU mode. + * with the current h/w there is no way to detect this. + * and since we dont have internal PMU lets do it under UMA-B chip id. + * we will change this when we will have internal PMU. + */ + if (Adapter->PmuMode == HYBRID_MODE_7C) { + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + uiResetValue = 0x1322a8; + retval = wrmalt(Adapter, (UINT)0x0f000d1c, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + uiResetValue = 0x132296; + retval = wrmalt(Adapter, (UINT)0x0f000d14, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + } else if (Adapter->PmuMode == HYBRID_MODE_6) { + + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + uiResetValue = 0x6003229a; + retval = wrmalt(Adapter, (UINT)0x0f000d14, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + retval = rdmalt(Adapter, (UINT)0x0f000c00, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + uiResetValue = 0x1322a8; + retval = wrmalt(Adapter, (UINT)0x0f000d1c, &uiResetValue, sizeof(uiResetValue)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, CMHOST, RDM, DBG_LVL_ALL, "%s:%d RDM failed\n", __func__, __LINE__); + return retval; + } + } + + } + Adapter->bDDRInitDone = TRUE; + return retval; +} + +int download_ddr_settings(struct bcm_mini_adapter *Adapter) +{ + struct bcm_ddr_setting *psDDRSetting = NULL; + ULONG RegCount = 0; + unsigned long ul_ddr_setting_load_addr = DDR_DUMP_INTERNAL_DEVICE_MEMORY; + UINT value = 0; + int retval = STATUS_SUCCESS; + bool bOverrideSelfRefresh = false; + + switch (Adapter->chip_id) { + case 0xbece3200: + switch (Adapter->DDRSetting) { + case DDR_80_MHZ: + psDDRSetting = asT3LP_DDRSetting80MHz; + RegCount = ARRAY_SIZE(asT3LP_DDRSetting80MHz); + RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ; + psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_80MHZ; + break; + case DDR_100_MHZ: + psDDRSetting = asT3LP_DDRSetting100MHz; + RegCount = ARRAY_SIZE(asT3LP_DDRSetting100MHz); + RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ; + psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_100MHZ; + break; + case DDR_133_MHZ: + bOverrideSelfRefresh = TRUE; + psDDRSetting = asT3LP_DDRSetting133MHz; + RegCount = ARRAY_SIZE(asT3LP_DDRSetting133MHz); + RegCount -= T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ; + psDDRSetting += T3LP_SKIP_CLOCK_PROGRAM_DUMP_133MHZ; + break; + default: + return -EINVAL; + } + break; + + case T3LPB: + case BCS220_2: + case BCS220_2BC: + case BCS250_BC: + case BCS220_3: + switch (Adapter->DDRSetting) { + case DDR_80_MHZ: + psDDRSetting = asT3LPB_DDRSetting80MHz; + RegCount = ARRAY_SIZE(asT3LPB_DDRSetting80MHz); + RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ; + psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_80MHZ; + break; + case DDR_100_MHZ: + psDDRSetting = asT3LPB_DDRSetting100MHz; + RegCount = ARRAY_SIZE(asT3LPB_DDRSetting100MHz); + RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ; + psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_100MHZ; + break; + case DDR_133_MHZ: + bOverrideSelfRefresh = TRUE; + psDDRSetting = asT3LPB_DDRSetting133MHz; + RegCount = ARRAY_SIZE(asT3LPB_DDRSetting133MHz); + RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ; + psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_133MHZ; + break; + + case DDR_160_MHZ: + bOverrideSelfRefresh = TRUE; + psDDRSetting = asT3LPB_DDRSetting160MHz; + RegCount = ARRAY_SIZE(asT3LPB_DDRSetting160MHz); + RegCount -= T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ; + psDDRSetting += T3LPB_SKIP_CLOCK_PROGRAM_DUMP_160MHZ; + + break; + default: + return -EINVAL; + } + break; + case 0xbece0300: + switch (Adapter->DDRSetting) { + case DDR_80_MHZ: + psDDRSetting = asT3_DDRSetting80MHz; + RegCount = ARRAY_SIZE(asT3_DDRSetting80MHz); + RegCount -= T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ; + psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_80MHZ; + break; + case DDR_100_MHZ: + psDDRSetting = asT3_DDRSetting100MHz; + RegCount = ARRAY_SIZE(asT3_DDRSetting100MHz); + RegCount -= T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ; + psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_100MHZ; + break; + case DDR_133_MHZ: + psDDRSetting = asT3_DDRSetting133MHz; + RegCount = ARRAY_SIZE(asT3_DDRSetting133MHz); + RegCount -= T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ; + psDDRSetting += T3_SKIP_CLOCK_PROGRAM_DUMP_133MHZ; + break; + default: + return -EINVAL; + } + break; + case 0xbece0310: + { + switch (Adapter->DDRSetting) { + case DDR_80_MHZ: + psDDRSetting = asT3B_DDRSetting80MHz; + RegCount = ARRAY_SIZE(asT3B_DDRSetting80MHz); + RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ; + psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_80MHZ; + break; + case DDR_100_MHZ: + psDDRSetting = asT3B_DDRSetting100MHz; + RegCount = ARRAY_SIZE(asT3B_DDRSetting100MHz); + RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ; + psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_100MHZ; + break; + case DDR_133_MHZ: + bOverrideSelfRefresh = TRUE; + psDDRSetting = asT3B_DDRSetting133MHz; + RegCount = ARRAY_SIZE(asT3B_DDRSetting133MHz); + RegCount -= T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ; + psDDRSetting += T3B_SKIP_CLOCK_PROGRAM_DUMP_133MHZ; + break; + } + break; + } + default: + return -EINVAL; + } + /* total number of Register that has to be dumped */ + value = RegCount; + retval = wrmalt(Adapter, ul_ddr_setting_load_addr, &value, sizeof(value)); + if (retval) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__); + + return retval; + } + ul_ddr_setting_load_addr += sizeof(ULONG); + /* signature */ + value = (0x1d1e0dd0); + retval = wrmalt(Adapter, ul_ddr_setting_load_addr, &value, sizeof(value)); + if (retval) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__); + return retval; + } + + ul_ddr_setting_load_addr += sizeof(ULONG); + RegCount *= (sizeof(struct bcm_ddr_setting)/sizeof(ULONG)); + + while (RegCount && !retval) { + value = psDDRSetting->ulRegAddress; + retval = wrmalt(Adapter, ul_ddr_setting_load_addr, &value, sizeof(value)); + ul_ddr_setting_load_addr += sizeof(ULONG); + if (!retval) { + if (bOverrideSelfRefresh && (psDDRSetting->ulRegAddress == 0x0F007018)) { + value = (psDDRSetting->ulRegValue | (1<<8)); + if (STATUS_SUCCESS != wrmalt(Adapter, ul_ddr_setting_load_addr, + &value, sizeof(value))) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__); + break; + } + } else { + value = psDDRSetting->ulRegValue; + + if (STATUS_SUCCESS != wrmalt(Adapter, ul_ddr_setting_load_addr , + &value, sizeof(value))) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "%s:%d\n", __func__, __LINE__); + break; + } + } + } + ul_ddr_setting_load_addr += sizeof(ULONG); + RegCount--; + psDDRSetting++; + } + return retval; +} diff --git a/drivers/staging/bcm/DDRInit.h b/drivers/staging/bcm/DDRInit.h new file mode 100644 index 00000000000..b0196fce925 --- /dev/null +++ b/drivers/staging/bcm/DDRInit.h @@ -0,0 +1,9 @@ +#ifndef _DDR_INIT_H_ +#define _DDR_INIT_H_ + + + +int ddr_init(struct bcm_mini_adapter *psAdapter); +int download_ddr_settings(struct bcm_mini_adapter *psAdapter); + +#endif diff --git a/drivers/staging/bcm/Debug.h b/drivers/staging/bcm/Debug.h new file mode 100644 index 00000000000..7b331215c1a --- /dev/null +++ b/drivers/staging/bcm/Debug.h @@ -0,0 +1,242 @@ +/* + * Debug.h + * + * Dynamic (runtime) debug framework implementation. + * -kaiwan. + */ +#ifndef _DEBUG_H +#define _DEBUG_H +#include <linux/string.h> +#define NONE 0xFFFF + +/* TYPE and SUBTYPE + * Define valid TYPE (or category or code-path, however you like to think of it) + * and SUBTYPE s. + * Type and SubType are treated as bitmasks. + */ +#define DBG_TYPE_INITEXIT (1 << 0) /* 1 */ +#define DBG_TYPE_TX (1 << 1) /* 2 */ +#define DBG_TYPE_RX (1 << 2) /* 4 */ +#define DBG_TYPE_OTHERS (1 << 3) /* 8 */ +#define NUMTYPES 4 + +/* -SUBTYPEs for TX : TYPE is DBG_TYPE_TX -----// + * Transmit.c ,Arp.c, LeakyBucket.c, And Qos.c + * total 17 macros + */ +/* Transmit.c */ +#define TX 1 +#define MP_SEND (TX << 0) +#define NEXT_SEND (TX << 1) +#define TX_FIFO (TX << 2) +#define TX_CONTROL (TX << 3) + +/* Arp.c */ +#define IP_ADDR (TX << 4) +#define ARP_REQ (TX << 5) +#define ARP_RESP (TX << 6) + +/* Leakybucket.c */ +#define TOKEN_COUNTS (TX << 8) +#define CHECK_TOKENS (TX << 9) +#define TX_PACKETS (TX << 10) +#define TIMER (TX << 11) + +/* Qos.c */ +#define QOS TX +#define QUEUE_INDEX (QOS << 12) +#define IPV4_DBG (QOS << 13) +#define IPV6_DBG (QOS << 14) +#define PRUNE_QUEUE (QOS << 15) +#define SEND_QUEUE (QOS << 16) + +/* TX_Misc */ +#define TX_OSAL_DBG (TX << 17) + +/* --SUBTYPEs for ------INIT & EXIT--------------------- + * ------------ TYPE is DBG_TYPE_INITEXIT -----// + * DriverEntry.c, bcmfwup.c, ChipDetectTask.c, HaltnReset.c, InterfaceDDR.c + */ +#define MP 1 +#define DRV_ENTRY (MP << 0) +#define MP_INIT (MP << 1) +#define READ_REG (MP << 3) +#define DISPATCH (MP << 2) +#define CLAIM_ADAP (MP << 4) +#define REG_IO_PORT (MP << 5) +#define INIT_DISP (MP << 6) +#define RX_INIT (MP << 7) + +/* -SUBTYPEs for --RX---------------------------------- + * ------------RX : TYPE is DBG_TYPE_RX -----// + * Receive.c + */ +#define RX 1 +#define RX_DPC (RX << 0) +#define RX_CTRL (RX << 3) +#define RX_DATA (RX << 4) +#define MP_RETURN (RX << 1) +#define LINK_MSG (RX << 2) + +/* -SUBTYPEs for ----OTHER ROUTINES------------------ + * ------------OTHERS : TYPE is DBG_TYPE_OTHER -----// + * HaltnReset,CheckForHang,PnP,Misc,CmHost + * total 12 macros + */ +#define OTHERS 1 +#define ISR OTHERS +#define MP_DPC (ISR << 0) + +/* HaltnReset.c */ +#define HALT OTHERS +#define MP_HALT (HALT << 1) +#define CHECK_HANG (HALT << 2) +#define MP_RESET (HALT << 3) +#define MP_SHUTDOWN (HALT << 4) + +/* pnp.c */ +#define PNP OTHERS +#define MP_PNP (PNP << 5) + +/* Misc.c */ +#define MISC OTHERS +#define DUMP_INFO (MISC << 6) +#define CLASSIFY (MISC << 7) +#define LINK_UP_MSG (MISC << 8) +#define CP_CTRL_PKT (MISC << 9) +#define DUMP_CONTROL (MISC << 10) +#define LED_DUMP_INFO (MISC << 11) + +/* CmHost.c */ +#define CMHOST OTHERS +#define SERIAL (OTHERS << 12) +#define IDLE_MODE (OTHERS << 13) +#define WRM (OTHERS << 14) +#define RDM (OTHERS << 15) + +/* TODO - put PHS_SEND in Tx PHS_RECEIVE in Rx path ? */ +#define PHS_SEND (OTHERS << 16) +#define PHS_RECEIVE (OTHERS << 17) +#define PHS_MODULE (OTHERS << 18) + +#define INTF_INIT (OTHERS << 19) +#define INTF_ERR (OTHERS << 20) +#define INTF_WARN (OTHERS << 21) +#define INTF_NORM (OTHERS << 22) + +#define IRP_COMPLETION (OTHERS << 23) +#define SF_DESCRIPTOR_CNTS (OTHERS << 24) +#define PHS_DISPATCH (OTHERS << 25) +#define OSAL_DBG (OTHERS << 26) +#define NVM_RW (OTHERS << 27) + +#define HOST_MIBS (OTHERS << 28) +#define CONN_MSG (CMHOST << 29) + +/* Debug level + * We have 8 debug levels, in (numerical) increasing order of verbosity. + * IMP: Currently implementing ONLY DBG_LVL_ALL , i.e. , all debug prints will + * appear (of course, iff global debug flag is ON and we match the Type and SubType). + * Finer granularity debug levels are currently not in use, although the feature exists. + * + * Another way to say this: + * All the debug prints currently have 'debug_level' set to DBG_LVL_ALL . + * You can compile-time change that to any of the below, if you wish to. However, as of now, there's + * no dynamic facility to have the userspace 'TestApp' set debug_level. Slated for future expansion. + */ +#define BCM_ALL 7 +#define BCM_LOW 6 +#define BCM_PRINT 5 +#define BCM_NORMAL 4 +#define BCM_MEDIUM 3 +#define BCM_SCREAM 2 +#define BCM_ERR 1 +/* Not meant for developer in debug prints. + * To be used to disable all prints by setting the DBG_LVL_CURR to this value + */ +#define BCM_NONE 0 + +/* The current driver logging level. + * Everything at this level and (numerically) lower (meaning higher prio) + * is logged. + * Replace 'BCM_ALL' in the DBG_LVL_CURR macro with the logging level desired. + * For eg. to set the logging level to 'errors only' use: + * #define DBG_LVL_CURR (BCM_ERR) + */ + +#define DBG_LVL_CURR (BCM_ALL) +#define DBG_LVL_ALL BCM_ALL + +/* ---Userspace mapping of Debug State. + * Delibrately matches that of the Windows driver.. + * The TestApp's ioctl passes this struct to us. + */ +struct bcm_user_debug_state { + unsigned int Subtype, Type; + unsigned int OnOff; +/* unsigned int debug_level; future expansion */ +} __packed; + +/* ---Kernel-space mapping of Debug State */ +struct bcm_debug_state { + unsigned int type; + /* A bitmap of 32 bits for Subtype per Type. + * Valid indexes in 'subtype' array are *only* 1,2,4 and 8, + * corresponding to valid Type values. Hence we use the 'Type' field + * as the index value, ignoring the array entries 0,3,5,6,7 ! + */ + unsigned int subtype[(NUMTYPES*2)+1]; + unsigned int debug_level; +}; +/* Instantiated in the Adapter structure + * We'll reuse the debug level parameter to include a bit (the MSB) to indicate whether or not + * we want the function's name printed. + */ +#define DBG_NO_FUNC_PRINT (1 << 31) +#define DBG_LVL_BITMASK 0xFF + +/* --- Only for direct printk's; "hidden" to API. */ +#define DBG_TYPE_PRINTK 3 + +#define BCM_DEBUG_PRINT(Adapter, Type, SubType, dbg_level, string, args...) \ + do { \ + if (DBG_TYPE_PRINTK == Type) \ + pr_info("%s:" string, __func__, ##args); \ + else if (Adapter && \ + (dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level && \ + (Type & Adapter->stDebugState.type) && \ + (SubType & Adapter->stDebugState.subtype[Type])) { \ + if (dbg_level & DBG_NO_FUNC_PRINT) \ + pr_debug("%s:\n", string); \ + else \ + pr_debug("%s:\n" string, __func__, ##args); \ + } \ + } while (0) + +#define BCM_DEBUG_PRINT_BUFFER(Adapter, Type, SubType, dbg_level, buffer, bufferlen) \ + do { \ + if (DBG_TYPE_PRINTK == Type || \ + (Adapter && \ + (dbg_level & DBG_LVL_BITMASK) <= Adapter->stDebugState.debug_level && \ + (Type & Adapter->stDebugState.type) && \ + (SubType & Adapter->stDebugState.subtype[Type]))) { \ + pr_debug("%s:\n", __func__); \ + print_hex_dump(KERN_DEBUG, " ", DUMP_PREFIX_OFFSET, \ + 16, 1, buffer, bufferlen, false); \ + } \ + } while (0) + +#define BCM_SHOW_DEBUG_BITMAP(Adapter) do { \ + int i; \ + for (i = 0; i < (NUMTYPES * 2) + 1; i++) { \ + if ((i == 1) || (i == 2) || (i == 4) || (i == 8)) { \ + /* CAUTION! Forcefully turn on ALL debug paths and subpaths! \ + * Adapter->stDebugState.subtype[i] = 0xffffffff; \ + */ \ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "subtype[%d] = 0x%08x\n", \ + i, Adapter->stDebugState.subtype[i]); \ + } \ + } \ +} while (0) + +#endif diff --git a/drivers/staging/bcm/HandleControlPacket.c b/drivers/staging/bcm/HandleControlPacket.c new file mode 100644 index 00000000000..495fe3dc514 --- /dev/null +++ b/drivers/staging/bcm/HandleControlPacket.c @@ -0,0 +1,235 @@ +/** + * @file HandleControlPacket.c + * This file contains the routines to deal with + * sending and receiving of control packets. + */ +#include "headers.h" + +/** + * When a control packet is received, analyze the + * "status" and call appropriate response function. + * Enqueue the control packet for Application. + * @return None + */ +static VOID handle_rx_control_packet(struct bcm_mini_adapter *Adapter, struct sk_buff *skb) +{ + struct bcm_tarang_data *pTarang = NULL; + bool HighPriorityMessage = false; + struct sk_buff *newPacket = NULL; + CHAR cntrl_msg_mask_bit = 0; + bool drop_pkt_flag = TRUE; + USHORT usStatus = *(PUSHORT)(skb->data); + + if (netif_msg_pktdata(Adapter)) + print_hex_dump(KERN_DEBUG, PFX "rx control: ", DUMP_PREFIX_NONE, + 16, 1, skb->data, skb->len, 0); + + switch (usStatus) { + case CM_RESPONSES: /* 0xA0 */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, + DBG_LVL_ALL, + "MAC Version Seems to be Non Multi-Classifier, rejected by Driver"); + HighPriorityMessage = TRUE; + break; + case CM_CONTROL_NEWDSX_MULTICLASSIFIER_RESP: + HighPriorityMessage = TRUE; + if (Adapter->LinkStatus == LINKUP_DONE) + CmControlResponseMessage(Adapter, + (skb->data + sizeof(USHORT))); + break; + case LINK_CONTROL_RESP: /* 0xA2 */ + case STATUS_RSP: /* 0xA1 */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, + DBG_LVL_ALL, "LINK_CONTROL_RESP"); + HighPriorityMessage = TRUE; + LinkControlResponseMessage(Adapter, + (skb->data + sizeof(USHORT))); + break; + case STATS_POINTER_RESP: /* 0xA6 */ + HighPriorityMessage = TRUE; + StatisticsResponse(Adapter, (skb->data + sizeof(USHORT))); + break; + case IDLE_MODE_STATUS: /* 0xA3 */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, + DBG_LVL_ALL, + "IDLE_MODE_STATUS Type Message Got from F/W"); + InterfaceIdleModeRespond(Adapter, (PUINT)(skb->data + + sizeof(USHORT))); + HighPriorityMessage = TRUE; + break; + + case AUTH_SS_HOST_MSG: + HighPriorityMessage = TRUE; + break; + + default: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, + DBG_LVL_ALL, "Got Default Response"); + /* Let the Application Deal with This Packet */ + break; + } + + /* Queue The Control Packet to The Application Queues */ + down(&Adapter->RxAppControlQueuelock); + + for (pTarang = Adapter->pTarangs; pTarang; pTarang = pTarang->next) { + if (Adapter->device_removed) + break; + + drop_pkt_flag = TRUE; + /* + * There are cntrl msg from A0 to AC. It has been mapped to 0 to + * C bit in the cntrl mask. + * Also, by default AD to BF has been masked to the rest of the + * bits... which wil be ON by default. + * if mask bit is enable to particular pkt status, send it out + * to app else stop it. + */ + cntrl_msg_mask_bit = (usStatus & 0x1F); + /* + * printk("\ninew msg mask bit which is disable in mask:%X", + * cntrl_msg_mask_bit); + */ + if (pTarang->RxCntrlMsgBitMask & (1 << cntrl_msg_mask_bit)) + drop_pkt_flag = false; + + if ((drop_pkt_flag == TRUE) || + (pTarang->AppCtrlQueueLen > MAX_APP_QUEUE_LEN) + || ((pTarang->AppCtrlQueueLen > + MAX_APP_QUEUE_LEN / 2) && + (HighPriorityMessage == false))) { + /* + * Assumption:- + * 1. every tarang manages it own dropped pkt + * statitistics + * 2. Total packet dropped per tarang will be equal to + * the sum of all types of dropped pkt by that + * tarang only. + */ + switch (*(PUSHORT)skb->data) { + case CM_RESPONSES: + pTarang->stDroppedAppCntrlMsgs.cm_responses++; + break; + case CM_CONTROL_NEWDSX_MULTICLASSIFIER_RESP: + pTarang->stDroppedAppCntrlMsgs.cm_control_newdsx_multiclassifier_resp++; + break; + case LINK_CONTROL_RESP: + pTarang->stDroppedAppCntrlMsgs.link_control_resp++; + break; + case STATUS_RSP: + pTarang->stDroppedAppCntrlMsgs.status_rsp++; + break; + case STATS_POINTER_RESP: + pTarang->stDroppedAppCntrlMsgs.stats_pointer_resp++; + break; + case IDLE_MODE_STATUS: + pTarang->stDroppedAppCntrlMsgs.idle_mode_status++; + break; + case AUTH_SS_HOST_MSG: + pTarang->stDroppedAppCntrlMsgs.auth_ss_host_msg++; + break; + default: + pTarang->stDroppedAppCntrlMsgs.low_priority_message++; + break; + } + + continue; + } + + newPacket = skb_clone(skb, GFP_KERNEL); + if (!newPacket) + break; + ENQUEUEPACKET(pTarang->RxAppControlHead, + pTarang->RxAppControlTail, newPacket); + pTarang->AppCtrlQueueLen++; + } + up(&Adapter->RxAppControlQueuelock); + wake_up(&Adapter->process_read_wait_queue); + dev_kfree_skb(skb); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, + "After wake_up_interruptible"); +} + +/** + * @ingroup ctrl_pkt_functions + * Thread to handle control pkt reception + */ +int control_packet_handler(struct bcm_mini_adapter *Adapter /* pointer to adapter object*/) +{ + struct sk_buff *ctrl_packet = NULL; + unsigned long flags = 0; + /* struct timeval tv; */ + /* int *puiBuffer = NULL; */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, DBG_LVL_ALL, + "Entering to make thread wait on control packet event!"); + while (1) { + wait_event_interruptible(Adapter->process_rx_cntrlpkt, + atomic_read(&Adapter->cntrlpktCnt) || + Adapter->bWakeUpDevice || + kthread_should_stop()); + + + if (kthread_should_stop()) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CP_CTRL_PKT, + DBG_LVL_ALL, "Exiting\n"); + return 0; + } + if (TRUE == Adapter->bWakeUpDevice) { + Adapter->bWakeUpDevice = false; + if ((false == Adapter->bTriedToWakeUpFromlowPowerMode) + && ((TRUE == Adapter->IdleMode) || + (TRUE == Adapter->bShutStatus))) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + CP_CTRL_PKT, DBG_LVL_ALL, + "Calling InterfaceAbortIdlemode\n"); + /* + * Adapter->bTriedToWakeUpFromlowPowerMode + * = TRUE; + */ + InterfaceIdleModeWakeup(Adapter); + } + continue; + } + + while (atomic_read(&Adapter->cntrlpktCnt)) { + spin_lock_irqsave(&Adapter->control_queue_lock, flags); + ctrl_packet = Adapter->RxControlHead; + if (ctrl_packet) { + DEQUEUEPACKET(Adapter->RxControlHead, + Adapter->RxControlTail); + /* Adapter->RxControlHead=ctrl_packet->next; */ + } + + spin_unlock_irqrestore(&Adapter->control_queue_lock, + flags); + handle_rx_control_packet(Adapter, ctrl_packet); + atomic_dec(&Adapter->cntrlpktCnt); + } + + SetUpTargetDsxBuffers(Adapter); + } + return STATUS_SUCCESS; +} + +INT flushAllAppQ(void) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + struct bcm_tarang_data *pTarang = NULL; + struct sk_buff *PacketToDrop = NULL; + for (pTarang = Adapter->pTarangs; pTarang; pTarang = pTarang->next) { + while (pTarang->RxAppControlHead != NULL) { + PacketToDrop = pTarang->RxAppControlHead; + DEQUEUEPACKET(pTarang->RxAppControlHead, + pTarang->RxAppControlTail); + dev_kfree_skb(PacketToDrop); + } + pTarang->AppCtrlQueueLen = 0; + /* dropped contrl packet statistics also should be reset. */ + memset((PVOID)&pTarang->stDroppedAppCntrlMsgs, 0, + sizeof(struct bcm_mibs_dropped_cntrl_msg)); + + } + return STATUS_SUCCESS; +} + + diff --git a/drivers/staging/bcm/HostMIBSInterface.h b/drivers/staging/bcm/HostMIBSInterface.h new file mode 100644 index 00000000000..f922ac49b70 --- /dev/null +++ b/drivers/staging/bcm/HostMIBSInterface.h @@ -0,0 +1,192 @@ +#ifndef _HOST_MIBSINTERFACE_H +#define _HOST_MIBSINTERFACE_H + +/* + * Copyright (c) 2007 Beceem Communications Pvt. Ltd + * File Name: HostMIBSInterface.h + * Abstract: This file contains DS used by the Host to update the Host + * statistics used for the MIBS. + */ + +#define MIBS_MAX_CLASSIFIERS 100 +#define MIBS_MAX_PHSRULES 100 +#define MIBS_MAX_SERVICEFLOWS 17 +#define MIBS_MAX_IP_RANGE_LENGTH 4 +#define MIBS_MAX_PORT_RANGE 4 +#define MIBS_MAX_PROTOCOL_LENGTH 32 +#define MIBS_MAX_PHS_LENGTHS 255 +#define MIBS_IPV6_ADDRESS_SIZEINBYTES 0x10 +#define MIBS_IP_LENGTH_OF_ADDRESS 4 +#define MIBS_MAX_HIST_ENTRIES 12 +#define MIBS_PKTSIZEHIST_RANGE 128 + +union bcm_mibs_ip_addr { + struct { + /* Source Ip Address Range */ + unsigned long ulIpv4Addr[MIBS_MAX_IP_RANGE_LENGTH]; + /* Source Ip Mask Address Range */ + unsigned long ulIpv4Mask[MIBS_MAX_IP_RANGE_LENGTH]; + }; + struct { + /* Source Ip Address Range */ + unsigned long ulIpv6Addr[MIBS_MAX_IP_RANGE_LENGTH * 4]; + /* Source Ip Mask Address Range */ + unsigned long ulIpv6Mask[MIBS_MAX_IP_RANGE_LENGTH * 4]; + }; + struct { + unsigned char ucIpv4Address[MIBS_MAX_IP_RANGE_LENGTH * MIBS_IP_LENGTH_OF_ADDRESS]; + unsigned char ucIpv4Mask[MIBS_MAX_IP_RANGE_LENGTH * MIBS_IP_LENGTH_OF_ADDRESS]; + }; + struct { + unsigned char ucIpv6Address[MIBS_MAX_IP_RANGE_LENGTH * MIBS_IPV6_ADDRESS_SIZEINBYTES]; + unsigned char ucIpv6Mask[MIBS_MAX_IP_RANGE_LENGTH * MIBS_IPV6_ADDRESS_SIZEINBYTES]; + }; +}; + +struct bcm_mibs_host_info { + u64 GoodTransmits; + u64 GoodReceives; + /* this to keep track of the Tx and Rx MailBox Registers. */ + unsigned long NumDesUsed; + unsigned long CurrNumFreeDesc; + unsigned long PrevNumFreeDesc; + /* to keep track the no of byte received */ + unsigned long PrevNumRcevBytes; + unsigned long CurrNumRcevBytes; + /* QOS Related */ + unsigned long BEBucketSize; + unsigned long rtPSBucketSize; + unsigned long LastTxQueueIndex; + bool TxOutofDescriptors; + bool TimerActive; + u32 u32TotalDSD; + u32 aTxPktSizeHist[MIBS_MAX_HIST_ENTRIES]; + u32 aRxPktSizeHist[MIBS_MAX_HIST_ENTRIES]; +}; + +struct bcm_mibs_classifier_rule { + unsigned long ulSFID; + unsigned char ucReserved[2]; + u16 uiClassifierRuleIndex; + bool bUsed; + unsigned short usVCID_Value; + u8 u8ClassifierRulePriority; + union bcm_mibs_ip_addr stSrcIpAddress; + /* IP Source Address Length */ + unsigned char ucIPSourceAddressLength; + union bcm_mibs_ip_addr stDestIpAddress; + /* IP Destination Address Length */ + unsigned char ucIPDestinationAddressLength; + unsigned char ucIPTypeOfServiceLength; + unsigned char ucTosLow; + unsigned char ucTosHigh; + unsigned char ucTosMask; + unsigned char ucProtocolLength; + unsigned char ucProtocol[MIBS_MAX_PROTOCOL_LENGTH]; + unsigned short usSrcPortRangeLo[MIBS_MAX_PORT_RANGE]; + unsigned short usSrcPortRangeHi[MIBS_MAX_PORT_RANGE]; + unsigned char ucSrcPortRangeLength; + unsigned short usDestPortRangeLo[MIBS_MAX_PORT_RANGE]; + unsigned short usDestPortRangeHi[MIBS_MAX_PORT_RANGE]; + unsigned char ucDestPortRangeLength; + bool bProtocolValid; + bool bTOSValid; + bool bDestIpValid; + bool bSrcIpValid; + unsigned char ucDirection; + bool bIpv6Protocol; + u32 u32PHSRuleID; +}; + +struct bcm_mibs_phs_rule { + unsigned long ulSFID; + u8 u8PHSI; + u8 u8PHSFLength; + u8 u8PHSF[MIBS_MAX_PHS_LENGTHS]; + u8 u8PHSMLength; + u8 u8PHSM[MIBS_MAX_PHS_LENGTHS]; + u8 u8PHSS; + u8 u8PHSV; + u8 reserved[5]; + long PHSModifiedBytes; + unsigned long PHSModifiedNumPackets; + unsigned long PHSErrorNumPackets; +}; + +struct bcm_mibs_parameters { + u32 wmanIfSfid; + u32 wmanIfCmnCpsSfState; + u32 wmanIfCmnCpsMaxSustainedRate; + u32 wmanIfCmnCpsMaxTrafficBurst; + u32 wmanIfCmnCpsMinReservedRate; + u32 wmanIfCmnCpsToleratedJitter; + u32 wmanIfCmnCpsMaxLatency; + u32 wmanIfCmnCpsFixedVsVariableSduInd; + u32 wmanIfCmnCpsSduSize; + u32 wmanIfCmnCpsSfSchedulingType; + u32 wmanIfCmnCpsArqEnable; + u32 wmanIfCmnCpsArqWindowSize; + u32 wmanIfCmnCpsArqBlockLifetime; + u32 wmanIfCmnCpsArqSyncLossTimeout; + u32 wmanIfCmnCpsArqDeliverInOrder; + u32 wmanIfCmnCpsArqRxPurgeTimeout; + u32 wmanIfCmnCpsArqBlockSize; + u32 wmanIfCmnCpsMinRsvdTolerableRate; + u32 wmanIfCmnCpsReqTxPolicy; + u32 wmanIfCmnSfCsSpecification; + u32 wmanIfCmnCpsTargetSaid; +}; + +struct bcm_mibs_table { + unsigned long ulSFID; + unsigned short usVCID_Value; + unsigned int uiThreshold; + u8 u8TrafficPriority; + bool bValid; + bool bActive; + bool bActivateRequestSent; + u8 u8QueueType; + unsigned int uiMaxBucketSize; + unsigned int uiCurrentQueueDepthOnTarget; + unsigned int uiCurrentBytesOnHost; + unsigned int uiCurrentPacketsOnHost; + unsigned int uiDroppedCountBytes; + unsigned int uiDroppedCountPackets; + unsigned int uiSentBytes; + unsigned int uiSentPackets; + unsigned int uiCurrentDrainRate; + unsigned int uiThisPeriodSentBytes; + u64 liDrainCalculated; + unsigned int uiCurrentTokenCount; + u64 liLastUpdateTokenAt; + unsigned int uiMaxAllowedRate; + unsigned int NumOfPacketsSent; + unsigned char ucDirection; + unsigned short usCID; + struct bcm_mibs_parameters stMibsExtServiceFlowTable; + unsigned int uiCurrentRxRate; + unsigned int uiThisPeriodRxBytes; + unsigned int uiTotalRxBytes; + unsigned int uiTotalTxBytes; +}; + +struct bcm_mibs_dropped_cntrl_msg { + unsigned long cm_responses; + unsigned long cm_control_newdsx_multiclassifier_resp; + unsigned long link_control_resp; + unsigned long status_rsp; + unsigned long stats_pointer_resp; + unsigned long idle_mode_status; + unsigned long auth_ss_host_msg; + unsigned long low_priority_message; +}; + +struct bcm_host_stats_mibs { + struct bcm_mibs_host_info stHostInfo; + struct bcm_mibs_classifier_rule astClassifierTable[MIBS_MAX_CLASSIFIERS]; + struct bcm_mibs_table astSFtable[MIBS_MAX_SERVICEFLOWS]; + struct bcm_mibs_phs_rule astPhsRulesTable[MIBS_MAX_PHSRULES]; + struct bcm_mibs_dropped_cntrl_msg stDroppedAppCntrlMsgs; +}; + +#endif diff --git a/drivers/staging/bcm/IPv6Protocol.c b/drivers/staging/bcm/IPv6Protocol.c new file mode 100644 index 00000000000..cd160670e02 --- /dev/null +++ b/drivers/staging/bcm/IPv6Protocol.c @@ -0,0 +1,451 @@ +#include "headers.h" + +static bool MatchSrcIpv6Address(struct bcm_classifier_rule *pstClassifierRule, + struct bcm_ipv6_hdr *pstIpv6Header); +static bool MatchDestIpv6Address(struct bcm_classifier_rule *pstClassifierRule, + struct bcm_ipv6_hdr *pstIpv6Header); +static VOID DumpIpv6Header(struct bcm_ipv6_hdr *pstIpv6Header); + +static UCHAR *GetNextIPV6ChainedHeader(UCHAR **ppucPayload, + UCHAR *pucNextHeader, bool *bParseDone, USHORT *pusPayloadLength) +{ + UCHAR *pucRetHeaderPtr = NULL; + UCHAR *pucPayloadPtr = NULL; + USHORT usNextHeaderOffset = 0 ; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + if ((ppucPayload == NULL) || (*pusPayloadLength == 0) || + (*bParseDone)) { + *bParseDone = TRUE; + return NULL; + } + + pucRetHeaderPtr = *ppucPayload; + pucPayloadPtr = *ppucPayload; + + if (!pucRetHeaderPtr || !pucPayloadPtr) { + *bParseDone = TRUE; + return NULL; + } + + /* Get the Nextt Header Type */ + *bParseDone = false; + + + switch (*pucNextHeader) { + case IPV6HDR_TYPE_HOPBYHOP: + { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 HopByHop Header"); + usNextHeaderOffset += sizeof(struct bcm_ipv6_options_hdr); + } + break; + + case IPV6HDR_TYPE_ROUTING: + { + struct bcm_ipv6_routing_hdr *pstIpv6RoutingHeader; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 Routing Header"); + pstIpv6RoutingHeader = (struct bcm_ipv6_routing_hdr *)pucPayloadPtr; + usNextHeaderOffset += sizeof(struct bcm_ipv6_routing_hdr); + usNextHeaderOffset += pstIpv6RoutingHeader->ucNumAddresses * IPV6_ADDRESS_SIZEINBYTES; + + } + break; + case IPV6HDR_TYPE_FRAGMENTATION: + { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "\nIPv6 Fragmentation Header"); + usNextHeaderOffset += sizeof(struct bcm_ipv6_fragment_hdr); + + } + break; + case IPV6HDR_TYPE_DESTOPTS: + { + struct bcm_ipv6_dest_options_hdr *pstIpv6DestOptsHdr = (struct bcm_ipv6_dest_options_hdr *)pucPayloadPtr; + int nTotalOptions = pstIpv6DestOptsHdr->ucHdrExtLen; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "\nIPv6 DestOpts Header Header"); + usNextHeaderOffset += sizeof(struct bcm_ipv6_dest_options_hdr); + usNextHeaderOffset += nTotalOptions * IPV6_DESTOPTS_HDR_OPTIONSIZE ; + + } + break; + case IPV6HDR_TYPE_AUTHENTICATION: + { + struct bcm_ipv6_authentication_hdr *pstIpv6AuthHdr = (struct bcm_ipv6_authentication_hdr *)pucPayloadPtr; + int nHdrLen = pstIpv6AuthHdr->ucLength; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "\nIPv6 Authentication Header"); + usNextHeaderOffset += nHdrLen * 4; + } + break; + case IPV6HDR_TYPE_ENCRYPTEDSECURITYPAYLOAD: + { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "\nIPv6 Encrypted Security Payload Header"); + *bParseDone = TRUE; + + } + break; + case IPV6_ICMP_HDR_TYPE: + { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nICMP Header"); + *bParseDone = TRUE; + } + break; + case TCP_HEADER_TYPE: + { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nTCP Header"); + *bParseDone = TRUE; + } + break; + case UDP_HEADER_TYPE: + { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nUDP Header"); + *bParseDone = TRUE; + } + break; + default: + { + *bParseDone = TRUE; + + } + break; + + + } + + if (*bParseDone == false) { + if (*pusPayloadLength <= usNextHeaderOffset) { + *bParseDone = TRUE; + } else { + *pucNextHeader = *pucPayloadPtr; + pucPayloadPtr += usNextHeaderOffset; + (*pusPayloadLength) -= usNextHeaderOffset; + } + + } + + *ppucPayload = pucPayloadPtr; + return pucRetHeaderPtr; +} + + +static UCHAR GetIpv6ProtocolPorts(UCHAR *pucPayload, USHORT *pusSrcPort, + USHORT *pusDestPort, USHORT usPayloadLength, UCHAR ucNextHeader) +{ + UCHAR *pIpv6HdrScanContext = pucPayload; + bool bDone = false; + UCHAR ucHeaderType = 0; + UCHAR *pucNextHeader = NULL; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + if (!pucPayload || (usPayloadLength == 0)) + return 0; + + *pusSrcPort = *pusDestPort = 0; + ucHeaderType = ucNextHeader; + while (!bDone) { + pucNextHeader = GetNextIPV6ChainedHeader(&pIpv6HdrScanContext, + &ucHeaderType, &bDone, &usPayloadLength); + if (bDone) { + if ((ucHeaderType == TCP_HEADER_TYPE) || + (ucHeaderType == UDP_HEADER_TYPE)) { + *pusSrcPort = *((PUSHORT)(pucNextHeader)); + *pusDestPort = *((PUSHORT)(pucNextHeader+2)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "\nProtocol Ports - Src Port :0x%x Dest Port : 0x%x", + ntohs(*pusSrcPort), + ntohs(*pusDestPort)); + } + break; + + } + } + return ucHeaderType; +} + + +/* + * Arg 1 struct bcm_mini_adapter *Adapter is a pointer ot the driver contorl structure + * Arg 2 PVOID pcIpHeader is a pointer to the IP header of the packet + */ +USHORT IpVersion6(struct bcm_mini_adapter *Adapter, PVOID pcIpHeader, + struct bcm_classifier_rule *pstClassifierRule) +{ + USHORT ushDestPort = 0; + USHORT ushSrcPort = 0; + UCHAR ucNextProtocolAboveIP = 0; + struct bcm_ipv6_hdr *pstIpv6Header = NULL; + bool bClassificationSucceed = false; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "IpVersion6 ==========>\n"); + + pstIpv6Header = pcIpHeader; + + DumpIpv6Header(pstIpv6Header); + + /* + * Try to get the next higher layer protocol + * and the Ports Nos if TCP or UDP + */ + ucNextProtocolAboveIP = GetIpv6ProtocolPorts((UCHAR *)(pcIpHeader + sizeof(struct bcm_ipv6_hdr)), + &ushSrcPort, + &ushDestPort, + pstIpv6Header->usPayloadLength, + pstIpv6Header->ucNextHeader); + + do { + if (pstClassifierRule->ucDirection == 0) { + /* + * cannot be processed for classification. + * it is a down link connection + */ + break; + } + + if (!pstClassifierRule->bIpv6Protocol) { + /* + * We are looking for Ipv6 Classifiers + * Lets ignore this classifier and try the next one + */ + break; + } + + bClassificationSucceed = MatchSrcIpv6Address(pstClassifierRule, + pstIpv6Header); + if (!bClassificationSucceed) + break; + + bClassificationSucceed = MatchDestIpv6Address(pstClassifierRule, + pstIpv6Header); + if (!bClassificationSucceed) + break; + + /* + * Match the protocol type. + * For IPv6 the next protocol at end of + * Chain of IPv6 prot headers + */ + bClassificationSucceed = MatchProtocol(pstClassifierRule, + ucNextProtocolAboveIP); + if (!bClassificationSucceed) + break; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 Protocol Matched"); + + if ((ucNextProtocolAboveIP == TCP_HEADER_TYPE) || + (ucNextProtocolAboveIP == UDP_HEADER_TYPE)) { + /* Match Src Port */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 Source Port:%x\n", + ntohs(ushSrcPort)); + bClassificationSucceed = MatchSrcPort(pstClassifierRule, + ntohs(ushSrcPort)); + if (!bClassificationSucceed) + break; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 Src Port Matched"); + + /* Match Dest Port */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 Destination Port:%x\n", + ntohs(ushDestPort)); + bClassificationSucceed = MatchDestPort(pstClassifierRule, + ntohs(ushDestPort)); + if (!bClassificationSucceed) + break; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, "\nIPv6 Dest Port Matched"); + } + } while (0); + + if (bClassificationSucceed == TRUE) { + INT iMatchedSFQueueIndex = 0; + iMatchedSFQueueIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID); + if (iMatchedSFQueueIndex >= NO_OF_QUEUES) { + bClassificationSucceed = false; + } else { + if (Adapter->PackInfo[iMatchedSFQueueIndex].bActive == false) + bClassificationSucceed = false; + } + } + + return bClassificationSucceed; +} + + +static bool MatchSrcIpv6Address(struct bcm_classifier_rule *pstClassifierRule, + struct bcm_ipv6_hdr *pstIpv6Header) +{ + UINT uiLoopIndex = 0; + UINT uiIpv6AddIndex = 0; + UINT uiIpv6AddrNoLongWords = 4; + ULONG aulSrcIP[4]; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + /* + * This is the no. of Src Addresses ie Range of IP Addresses contained + * in the classifier rule for which we need to match + */ + UINT uiCountIPSrcAddresses = (UINT)pstClassifierRule->ucIPSourceAddressLength; + + + if (uiCountIPSrcAddresses == 0) + return TRUE; + + + /* First Convert the Ip Address in the packet to Host Endian order */ + for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) + aulSrcIP[uiIpv6AddIndex] = ntohl(pstIpv6Header->ulSrcIpAddress[uiIpv6AddIndex]); + + for (uiLoopIndex = 0; uiLoopIndex < uiCountIPSrcAddresses; uiLoopIndex += uiIpv6AddrNoLongWords) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "\n Src Ipv6 Address In Received Packet :\n "); + DumpIpv6Address(aulSrcIP); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "\n Src Ipv6 Mask In Classifier Rule:\n"); + DumpIpv6Address(&pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "\n Src Ipv6 Address In Classifier Rule :\n"); + DumpIpv6Address(&pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex]); + + for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) { + if ((pstClassifierRule->stSrcIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulSrcIP[uiIpv6AddIndex]) + != pstClassifierRule->stSrcIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) { + /* + * Match failed for current Ipv6 Address + * Try next Ipv6 Address + */ + break; + } + + if (uiIpv6AddIndex == uiIpv6AddrNoLongWords-1) { + /* Match Found */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "Ipv6 Src Ip Address Matched\n"); + return TRUE; + } + } + } + return false; +} + +static bool MatchDestIpv6Address(struct bcm_classifier_rule *pstClassifierRule, + struct bcm_ipv6_hdr *pstIpv6Header) +{ + UINT uiLoopIndex = 0; + UINT uiIpv6AddIndex = 0; + UINT uiIpv6AddrNoLongWords = 4; + ULONG aulDestIP[4]; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + /* + * This is the no. of Destination Addresses + * ie Range of IP Addresses contained in the classifier rule + * for which we need to match + */ + UINT uiCountIPDestinationAddresses = (UINT)pstClassifierRule->ucIPDestinationAddressLength; + + + if (uiCountIPDestinationAddresses == 0) + return TRUE; + + + /* First Convert the Ip Address in the packet to Host Endian order */ + for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) + aulDestIP[uiIpv6AddIndex] = ntohl(pstIpv6Header->ulDestIpAddress[uiIpv6AddIndex]); + + for (uiLoopIndex = 0; uiLoopIndex < uiCountIPDestinationAddresses; uiLoopIndex += uiIpv6AddrNoLongWords) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "\n Destination Ipv6 Address In Received Packet :\n "); + DumpIpv6Address(aulDestIP); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "\n Destination Ipv6 Mask In Classifier Rule :\n"); + DumpIpv6Address(&pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "\n Destination Ipv6 Address In Classifier Rule :\n"); + DumpIpv6Address(&pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex]); + + for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) { + if ((pstClassifierRule->stDestIpAddress.ulIpv6Mask[uiLoopIndex+uiIpv6AddIndex] & aulDestIP[uiIpv6AddIndex]) + != pstClassifierRule->stDestIpAddress.ulIpv6Addr[uiLoopIndex+uiIpv6AddIndex]) { + /* + * Match failed for current Ipv6 Address. + * Try next Ipv6 Address + */ + break; + } + + if (uiIpv6AddIndex == uiIpv6AddrNoLongWords-1) { + /* Match Found */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, + DBG_LVL_ALL, + "Ipv6 Destination Ip Address Matched\n"); + return TRUE; + } + } + } + return false; + +} + +VOID DumpIpv6Address(ULONG *puIpv6Address) +{ + UINT uiIpv6AddrNoLongWords = 4; + UINT uiIpv6AddIndex = 0; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + for (uiIpv6AddIndex = 0; uiIpv6AddIndex < uiIpv6AddrNoLongWords; uiIpv6AddIndex++) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + ":%lx", puIpv6Address[uiIpv6AddIndex]); + } + +} + +static VOID DumpIpv6Header(struct bcm_ipv6_hdr *pstIpv6Header) +{ + UCHAR ucVersion; + UCHAR ucPrio; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "----Ipv6 Header---"); + ucVersion = pstIpv6Header->ucVersionPrio & 0xf0; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Version : %x\n", ucVersion); + ucPrio = pstIpv6Header->ucVersionPrio & 0x0f; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Priority : %x\n", ucPrio); + /* + * BCM_DEBUG_PRINT( Adapter,DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + * "Flow Label : %x\n",(pstIpv6Header->ucVersionPrio &0xf0); + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Payload Length : %x\n", + ntohs(pstIpv6Header->usPayloadLength)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Next Header : %x\n", pstIpv6Header->ucNextHeader); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Hop Limit : %x\n", pstIpv6Header->ucHopLimit); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Src Address :\n"); + DumpIpv6Address(pstIpv6Header->ulSrcIpAddress); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "Dest Address :\n"); + DumpIpv6Address(pstIpv6Header->ulDestIpAddress); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV6_DBG, DBG_LVL_ALL, + "----Ipv6 Header End---"); + + +} diff --git a/drivers/staging/bcm/IPv6ProtocolHdr.h b/drivers/staging/bcm/IPv6ProtocolHdr.h new file mode 100644 index 00000000000..96b36a579af --- /dev/null +++ b/drivers/staging/bcm/IPv6ProtocolHdr.h @@ -0,0 +1,85 @@ +#ifndef _IPV6_PROTOCOL_DEFINES_ +#define _IPV6_PROTOCOL_DEFINES_ + +#define IPV6HDR_TYPE_HOPBYHOP 0x0 +#define IPV6HDR_TYPE_ROUTING 0x2B +#define IPV6HDR_TYPE_FRAGMENTATION 0x2C +#define IPV6HDR_TYPE_DESTOPTS 0x3c +#define IPV6HDR_TYPE_AUTHENTICATION 0x33 +#define IPV6HDR_TYPE_ENCRYPTEDSECURITYPAYLOAD 0x34 +#define MASK_IPV6_CS_SPEC 0x2 + +#define TCP_HEADER_TYPE 0x6 +#define UDP_HEADER_TYPE 0x11 +#define IPV6_ICMP_HDR_TYPE 0x2 +#define IPV6_FLOWLABEL_BITOFFSET 9 + +#define IPV6_MAX_CHAINEDHDR_BUFFBYTES 0x64 +/* + * Size of Dest Options field of Destinations Options Header + * in bytes. + */ +#define IPV6_DESTOPTS_HDR_OPTIONSIZE 0x8 + +struct bcm_ipv6_hdr { + unsigned char ucVersionPrio; + unsigned char aucFlowLabel[3]; + unsigned short usPayloadLength; + unsigned char ucNextHeader; + unsigned char ucHopLimit; + unsigned long ulSrcIpAddress[4]; + unsigned long ulDestIpAddress[4]; +}; + +struct bcm_ipv6_routing_hdr { + unsigned char ucNextHeader; + unsigned char ucRoutingType; + unsigned char ucNumAddresses; + unsigned char ucNextAddress; + unsigned long ulReserved; +}; + +struct bcm_ipv6_fragment_hdr { + unsigned char ucNextHeader; + unsigned char ucReserved; + unsigned short usFragmentOffset; + unsigned long ulIdentification; +}; + +struct bcm_ipv6_dest_options_hdr { + unsigned char ucNextHeader; + unsigned char ucHdrExtLen; + unsigned char ucDestOptions[6]; +}; + +struct bcm_ipv6_options_hdr { + unsigned char ucNextHeader; + unsigned char ucMisc[3]; + unsigned long ulJumboPayloadLen; +}; + +struct bcm_ipv6_authentication_hdr { + unsigned char ucNextHeader; + unsigned char ucLength; + unsigned short usReserved; + unsigned long ulSecurityParametersIndex; +}; + +enum bcm_ipaddr_context { + eSrcIpAddress, + eDestIpAddress +}; + +/* Function Prototypes */ + +unsigned short IpVersion6(struct bcm_mini_adapter *Adapter, /* < Pointer to the driver control structure */ + void *pcIpHeader, /* <Pointer to the IP Hdr of the packet */ + struct bcm_classifier_rule *pstClassifierRule); + +void DumpIpv6Address(unsigned long *puIpv6Address); + +extern bool MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule, unsigned short ushSrcPort); +extern bool MatchDestPort(struct bcm_classifier_rule *pstClassifierRule, unsigned short ushSrcPort); +extern bool MatchProtocol(struct bcm_classifier_rule *pstClassifierRule, unsigned char ucProtocol); + +#endif diff --git a/drivers/staging/bcm/InterfaceAdapter.h b/drivers/staging/bcm/InterfaceAdapter.h new file mode 100644 index 00000000000..06a6b18bca4 --- /dev/null +++ b/drivers/staging/bcm/InterfaceAdapter.h @@ -0,0 +1,79 @@ +#ifndef _INTERFACE_ADAPTER_H +#define _INTERFACE_ADAPTER_H + +struct bcm_bulk_endpoint_in { + char *bulk_in_buffer; + size_t bulk_in_size; + unsigned char bulk_in_endpointAddr; + unsigned int bulk_in_pipe; +}; + +struct bcm_bulk_endpoint_out { + unsigned char bulk_out_buffer; + size_t bulk_out_size; + unsigned char bulk_out_endpointAddr; + unsigned int bulk_out_pipe; + /* this is used when int out endpoint is used as bulk out end point */ + unsigned char int_out_interval; +}; + +struct bcm_intr_endpoint_in { + char *int_in_buffer; + size_t int_in_size; + unsigned char int_in_endpointAddr; + unsigned char int_in_interval; + unsigned int int_in_pipe; +}; + +struct bcm_intr_endpoint_out { + char *int_out_buffer; + size_t int_out_size; + unsigned char int_out_endpointAddr; + unsigned char int_out_interval; + unsigned int int_out_pipe; +}; + +struct bcm_usb_tcb { + struct urb *urb; + void *psIntfAdapter; + bool bUsed; +}; + +struct bcm_usb_rcb { + struct urb *urb; + void *psIntfAdapter; + bool bUsed; +}; + +/* + * This is the interface specific Sub-Adapter + * Structure. + */ +struct bcm_interface_adapter { + struct usb_device *udev; + struct usb_interface *interface; + /* Bulk endpoint in info */ + struct bcm_bulk_endpoint_in sBulkIn; + /* Bulk endpoint out info */ + struct bcm_bulk_endpoint_out sBulkOut; + /* Interrupt endpoint in info */ + struct bcm_intr_endpoint_in sIntrIn; + /* Interrupt endpoint out info */ + struct bcm_intr_endpoint_out sIntrOut; + unsigned long ulInterruptData[2]; + struct urb *psInterruptUrb; + struct bcm_usb_tcb asUsbTcb[MAXIMUM_USB_TCB]; + struct bcm_usb_rcb asUsbRcb[MAXIMUM_USB_RCB]; + atomic_t uNumTcbUsed; + atomic_t uCurrTcb; + atomic_t uNumRcbUsed; + atomic_t uCurrRcb; + struct bcm_mini_adapter *psAdapter; + bool bFlashBoot; + bool bHighSpeedDevice; + bool bSuspended; + bool bPreparingForBusSuspend; + struct work_struct usbSuspendWork; +}; + +#endif diff --git a/drivers/staging/bcm/InterfaceDld.c b/drivers/staging/bcm/InterfaceDld.c new file mode 100644 index 00000000000..e1925bdc127 --- /dev/null +++ b/drivers/staging/bcm/InterfaceDld.c @@ -0,0 +1,316 @@ +#include "headers.h" + +int InterfaceFileDownload(PVOID arg, struct file *flp, unsigned int on_chip_loc) +{ + /* unsigned int reg = 0; */ + mm_segment_t oldfs = {0}; + int errno = 0, len = 0; /* ,is_config_file = 0 */ + loff_t pos = 0; + struct bcm_interface_adapter *psIntfAdapter = arg; + /* struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter; */ + char *buff = kmalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL); + + if (!buff) + return -ENOMEM; + + while (1) { + oldfs = get_fs(); + set_fs(get_ds()); + len = vfs_read(flp, (void __force __user *)buff, + MAX_TRANSFER_CTRL_BYTE_USB, &pos); + set_fs(oldfs); + if (len <= 0) { + if (len < 0) + errno = len; + else + errno = 0; + break; + } + /* BCM_DEBUG_PRINT_BUFFER(Adapter,DBG_TYPE_INITEXIT, MP_INIT, + * DBG_LVL_ALL, buff, + * MAX_TRANSFER_CTRL_BYTE_USB); + */ + errno = InterfaceWRM(psIntfAdapter, on_chip_loc, buff, len); + if (errno) + break; + on_chip_loc += MAX_TRANSFER_CTRL_BYTE_USB; + } + + kfree(buff); + return errno; +} + +int InterfaceFileReadbackFromChip(PVOID arg, struct file *flp, + unsigned int on_chip_loc) +{ + char *buff, *buff_readback; + unsigned int reg = 0; + mm_segment_t oldfs = {0}; + int errno = 0, len = 0, is_config_file = 0; + loff_t pos = 0; + static int fw_down; + INT Status = STATUS_SUCCESS; + struct bcm_interface_adapter *psIntfAdapter = arg; + int bytes; + + buff = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_DMA); + buff_readback = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB , GFP_DMA); + if (!buff || !buff_readback) { + kfree(buff); + kfree(buff_readback); + + return -ENOMEM; + } + + is_config_file = (on_chip_loc == CONFIG_BEGIN_ADDR) ? 1 : 0; + + while (1) { + oldfs = get_fs(); + set_fs(get_ds()); + len = vfs_read(flp, (void __force __user *)buff, + MAX_TRANSFER_CTRL_BYTE_USB, &pos); + set_fs(oldfs); + fw_down++; + + if (len <= 0) { + if (len < 0) + errno = len; + else + errno = 0; + break; + } + + bytes = InterfaceRDM(psIntfAdapter, on_chip_loc, + buff_readback, len); + if (bytes < 0) { + Status = bytes; + goto exit; + } + reg++; + if ((len-sizeof(unsigned int)) < 4) { + if (memcmp(buff_readback, buff, len)) { + Status = -EIO; + goto exit; + } + } else { + len -= 4; + + while (len) { + if (*(unsigned int *)&buff_readback[len] != + *(unsigned int *)&buff[len]) { + Status = -EIO; + goto exit; + } + len -= 4; + } + } + on_chip_loc += MAX_TRANSFER_CTRL_BYTE_USB; + } /* End of while(1) */ + +exit: + kfree(buff); + kfree(buff_readback); + return Status; +} + +static int bcm_download_config_file(struct bcm_mini_adapter *Adapter, + struct bcm_firmware_info *psFwInfo) +{ + int retval = STATUS_SUCCESS; + B_UINT32 value = 0; + + if (Adapter->pstargetparams == NULL) { + Adapter->pstargetparams = + kmalloc(sizeof(struct bcm_target_params), GFP_KERNEL); + if (Adapter->pstargetparams == NULL) + return -ENOMEM; + } + + if (psFwInfo->u32FirmwareLength != sizeof(struct bcm_target_params)) + return -EIO; + + retval = copy_from_user(Adapter->pstargetparams, + psFwInfo->pvMappedFirmwareAddress, + psFwInfo->u32FirmwareLength); + if (retval) { + kfree(Adapter->pstargetparams); + Adapter->pstargetparams = NULL; + return -EFAULT; + } + + /* Parse the structure and then Download the Firmware */ + beceem_parse_target_struct(Adapter); + + /* Initializing the NVM. */ + BcmInitNVM(Adapter); + retval = InitLedSettings(Adapter); + + if (retval) + return retval; + + if (Adapter->LEDInfo.led_thread_running & + BCM_LED_THREAD_RUNNING_ACTIVELY) { + Adapter->LEDInfo.bLedInitDone = false; + Adapter->DriverState = DRIVER_INIT; + wake_up(&Adapter->LEDInfo.notify_led_event); + } + + if (Adapter->LEDInfo.led_thread_running & + BCM_LED_THREAD_RUNNING_ACTIVELY) { + Adapter->DriverState = FW_DOWNLOAD; + wake_up(&Adapter->LEDInfo.notify_led_event); + } + + /* Initialize the DDR Controller */ + retval = ddr_init(Adapter); + if (retval) + return retval; + + value = 0; + wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 4, + &value, sizeof(value)); + wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 8, + &value, sizeof(value)); + + if (Adapter->eNVMType == NVM_FLASH) { + retval = PropagateCalParamsFromFlashToMemory(Adapter); + if (retval) + return retval; + } + + retval = buffDnldVerify(Adapter, (PUCHAR)Adapter->pstargetparams, + sizeof(struct bcm_target_params), CONFIG_BEGIN_ADDR); + + if (retval) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, + MP_INIT, DBG_LVL_ALL, + "configuration file not downloaded properly"); + else + Adapter->bCfgDownloaded = TRUE; + + return retval; +} + +int bcm_ioctl_fw_download(struct bcm_mini_adapter *Adapter, + struct bcm_firmware_info *psFwInfo) +{ + int retval = STATUS_SUCCESS; + PUCHAR buff = NULL; + + /* Config File is needed for the Driver to download the Config file and + * Firmware. Check for the Config file to be first to be sent from the + * Application + */ + atomic_set(&Adapter->uiMBupdate, false); + if (!Adapter->bCfgDownloaded && + psFwInfo->u32StartingAddress != CONFIG_BEGIN_ADDR) { + /* Can't Download Firmware. */ + return -EINVAL; + } + + /* If Config File, Finish the DDR Settings and then Download CFG File */ + if (psFwInfo->u32StartingAddress == CONFIG_BEGIN_ADDR) { + retval = bcm_download_config_file(Adapter, psFwInfo); + } else { + buff = kzalloc(psFwInfo->u32FirmwareLength, GFP_KERNEL); + if (buff == NULL) + return -ENOMEM; + + retval = copy_from_user(buff, + psFwInfo->pvMappedFirmwareAddress, + psFwInfo->u32FirmwareLength); + if (retval != STATUS_SUCCESS) { + retval = -EFAULT; + goto error; + } + + retval = buffDnldVerify(Adapter, + buff, + psFwInfo->u32FirmwareLength, + psFwInfo->u32StartingAddress); + + if (retval != STATUS_SUCCESS) + goto error; + } + +error: + kfree(buff); + return retval; +} + +static INT buffDnld(struct bcm_mini_adapter *Adapter, + PUCHAR mappedbuffer, UINT u32FirmwareLength, + ULONG u32StartingAddress) +{ + unsigned int len = 0; + int retval = STATUS_SUCCESS; + len = u32FirmwareLength; + + while (u32FirmwareLength) { + len = MIN_VAL(u32FirmwareLength, MAX_TRANSFER_CTRL_BYTE_USB); + retval = wrm(Adapter, u32StartingAddress, mappedbuffer, len); + + if (retval) + break; + u32StartingAddress += len; + u32FirmwareLength -= len; + mappedbuffer += len; + } + return retval; +} + +static INT buffRdbkVerify(struct bcm_mini_adapter *Adapter, + PUCHAR mappedbuffer, UINT u32FirmwareLength, + ULONG u32StartingAddress) +{ + UINT len = u32FirmwareLength; + INT retval = STATUS_SUCCESS; + PUCHAR readbackbuff = kzalloc(MAX_TRANSFER_CTRL_BYTE_USB, GFP_KERNEL); + int bytes; + + if (NULL == readbackbuff) + return -ENOMEM; + + while (u32FirmwareLength && !retval) { + len = MIN_VAL(u32FirmwareLength, MAX_TRANSFER_CTRL_BYTE_USB); + bytes = rdm(Adapter, u32StartingAddress, readbackbuff, len); + + if (bytes < 0) { + retval = bytes; + break; + } + + if (memcmp(readbackbuff, mappedbuffer, len) != 0) { + pr_err("%s() failed. The firmware doesn't match what was written", + __func__); + retval = -EIO; + } + + u32StartingAddress += len; + u32FirmwareLength -= len; + mappedbuffer += len; + + } /* end of while (u32FirmwareLength && !retval) */ + kfree(readbackbuff); + return retval; +} + +INT buffDnldVerify(struct bcm_mini_adapter *Adapter, + unsigned char *mappedbuffer, + unsigned int u32FirmwareLength, + unsigned long u32StartingAddress) +{ + INT status = STATUS_SUCCESS; + + status = buffDnld(Adapter, mappedbuffer, + u32FirmwareLength, u32StartingAddress); + if (status != STATUS_SUCCESS) + goto error; + + status = buffRdbkVerify(Adapter, mappedbuffer, + u32FirmwareLength, u32StartingAddress); + if (status != STATUS_SUCCESS) + goto error; +error: + return status; +} diff --git a/drivers/staging/bcm/InterfaceIdleMode.c b/drivers/staging/bcm/InterfaceIdleMode.c new file mode 100644 index 00000000000..c84ee494f55 --- /dev/null +++ b/drivers/staging/bcm/InterfaceIdleMode.c @@ -0,0 +1,275 @@ +#include "headers.h" + +/* +Function: InterfaceIdleModeWakeup + +Description: This is the hardware specific Function for + waking up HW device from Idle mode. + A software abort pattern is written to the + device to wake it and necessary power state + transitions from host are performed here. + +Input parameters: IN struct bcm_mini_adapter *Adapter + - Miniport Adapter Context + +Return: BCM_STATUS_SUCCESS - If Wakeup of the HW Interface + was successful. + Other - If an error occurred. +*/ + +/* +Function: InterfaceIdleModeRespond + +Description: This is the hardware specific Function for + responding to Idle mode request from target. + Necessary power state transitions from host for + idle mode or other device specific initializations + are performed here. + +Input parameters: IN struct bcm_mini_adapter * Adapter + - Miniport Adapter Context + +Return: BCM_STATUS_SUCCESS - If Idle mode response related + HW configuration was successful. + Other - If an error occurred. +*/ + +/* +"dmem bfc02f00 100" tells how many time device went in Idle mode. +this value will be at address bfc02fa4.just before value d0ea1dle. + +Set time value by writing at bfc02f98 7d0 + +checking the Ack timer expire on kannon by running command +d qcslog .. if it shows e means host has not send response +to f/w with in 200 ms. Response should be +send to f/w with in 200 ms after the Idle/Shutdown req issued + +*/ + + +int InterfaceIdleModeRespond(struct bcm_mini_adapter *Adapter, + unsigned int *puiBuffer) +{ + int status = STATUS_SUCCESS; + unsigned int uiRegRead = 0; + int bytes; + + if (ntohl(*puiBuffer) == GO_TO_IDLE_MODE_PAYLOAD) { + if (ntohl(*(puiBuffer+1)) == 0) { + + status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC, + &uiRegRead, sizeof(uiRegRead)); + if (status) + return status; + + if (Adapter->ulPowerSaveMode == + DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) { + uiRegRead = 0x00000000; + status = wrmalt(Adapter, + DEBUG_INTERRUPT_GENERATOR_REGISTOR, + &uiRegRead, sizeof(uiRegRead)); + if (status) + return status; + } + /* Below Register should not br read in case of + * Manual and Protocol Idle mode */ + else if (Adapter->ulPowerSaveMode != + DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) { + /* clear on read Register */ + bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG0, + &uiRegRead, sizeof(uiRegRead)); + if (bytes < 0) { + status = bytes; + return status; + } + /* clear on read Register */ + bytes = rdmalt(Adapter, DEVICE_INT_OUT_EP_REG1, + &uiRegRead, sizeof(uiRegRead)); + if (bytes < 0) { + status = bytes; + return status; + } + } + + /* Set Idle Mode Flag to False and + * Clear IdleMode reg. */ + Adapter->IdleMode = false; + Adapter->bTriedToWakeUpFromlowPowerMode = false; + + wake_up(&Adapter->lowpower_mode_wait_queue); + + } else { + if (TRUE == Adapter->IdleMode) + return status; + + uiRegRead = 0; + + if (Adapter->chip_id == BCS220_2 || + Adapter->chip_id == BCS220_2BC || + Adapter->chip_id == BCS250_BC || + Adapter->chip_id == BCS220_3) { + + bytes = rdmalt(Adapter, HPM_CONFIG_MSW, + &uiRegRead, sizeof(uiRegRead)); + if (bytes < 0) { + status = bytes; + return status; + } + + + uiRegRead |= (1<<17); + + status = wrmalt(Adapter, HPM_CONFIG_MSW, + &uiRegRead, sizeof(uiRegRead)); + if (status) + return status; + } + SendIdleModeResponse(Adapter); + } + } else if (ntohl(*puiBuffer) == IDLE_MODE_SF_UPDATE_MSG) { + OverrideServiceFlowParams(Adapter, puiBuffer); + } + return status; +} + +static int InterfaceAbortIdlemode(struct bcm_mini_adapter *Adapter, + unsigned int Pattern) +{ + int status = STATUS_SUCCESS; + unsigned int value; + unsigned int chip_id; + unsigned long timeout = 0, itr = 0; + + int lenwritten = 0; + unsigned char aucAbortPattern[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF}; + struct bcm_interface_adapter *psInterfaceAdapter = + Adapter->pvInterfaceAdapter; + + /* Abort Bus suspend if its already suspended */ + if ((TRUE == psInterfaceAdapter->bSuspended) && + (TRUE == Adapter->bDoSuspend)) + status = usb_autopm_get_interface( + psInterfaceAdapter->interface); + + if ((Adapter->ulPowerSaveMode == + DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) || + (Adapter->ulPowerSaveMode == + DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE)) { + /* write the SW abort pattern. */ + status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC, + &Pattern, sizeof(Pattern)); + if (status) + return status; + } + + if (Adapter->ulPowerSaveMode == + DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) { + value = 0x80000000; + status = wrmalt(Adapter, + DEBUG_INTERRUPT_GENERATOR_REGISTOR, + &value, sizeof(value)); + if (status) + return status; + } else if (Adapter->ulPowerSaveMode != + DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) { + /* + * Get a Interrupt Out URB and send 8 Bytes Down + * To be Done in Thread Context. + * Not using Asynchronous Mechanism. + */ + status = usb_interrupt_msg(psInterfaceAdapter->udev, + usb_sndintpipe(psInterfaceAdapter->udev, + psInterfaceAdapter->sIntrOut.int_out_endpointAddr), + aucAbortPattern, + 8, + &lenwritten, + 5000); + if (status) + return status; + else + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + IDLE_MODE, DBG_LVL_ALL, + "NOB Sent down :%d", lenwritten); + + /* mdelay(25); */ + + timeout = jiffies + msecs_to_jiffies(50); + while (time_after(timeout, jiffies)) { + itr++; + rdmalt(Adapter, CHIP_ID_REG, &chip_id, sizeof(UINT)); + if (0xbece3200 == (chip_id&~(0xF0))) + chip_id = chip_id&~(0xF0); + if (chip_id == Adapter->chip_id) + break; + } + if (time_before(timeout, jiffies)) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + IDLE_MODE, DBG_LVL_ALL, + "Not able to read chip-id even after 25 msec"); + else + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + IDLE_MODE, DBG_LVL_ALL, + "Number of completed iteration to" + "read chip-id :%lu", itr); + + status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC, + &Pattern, sizeof(status)); + if (status) + return status; + } + return status; +} +int InterfaceIdleModeWakeup(struct bcm_mini_adapter *Adapter) +{ + if (Adapter->bTriedToWakeUpFromlowPowerMode) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + IDLE_MODE, DBG_LVL_ALL, + "Wake up already attempted.. ignoring\n"); + } else { + Adapter->bTriedToWakeUpFromlowPowerMode = TRUE; + InterfaceAbortIdlemode(Adapter, Adapter->usIdleModePattern); + + } + return 0; +} + +void InterfaceHandleShutdownModeWakeup(struct bcm_mini_adapter *Adapter) +{ + unsigned int uiRegVal = 0; + INT Status = 0; + int bytes; + + if (Adapter->ulPowerSaveMode == + DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING) { + /* clear idlemode interrupt. */ + uiRegVal = 0; + Status = wrmalt(Adapter, + DEBUG_INTERRUPT_GENERATOR_REGISTOR, + &uiRegVal, sizeof(uiRegVal)); + if (Status) + return; + } + + else { + +/* clear Interrupt EP registers. */ + bytes = rdmalt(Adapter, + DEVICE_INT_OUT_EP_REG0, + &uiRegVal, sizeof(uiRegVal)); + if (bytes < 0) { + Status = bytes; + return; + } + + bytes = rdmalt(Adapter, + DEVICE_INT_OUT_EP_REG1, + &uiRegVal, sizeof(uiRegVal)); + if (bytes < 0) { + Status = bytes; + return; + } + } +} + diff --git a/drivers/staging/bcm/InterfaceIdleMode.h b/drivers/staging/bcm/InterfaceIdleMode.h new file mode 100644 index 00000000000..2ef64003aa8 --- /dev/null +++ b/drivers/staging/bcm/InterfaceIdleMode.h @@ -0,0 +1,15 @@ +#ifndef _INTERFACE_IDLEMODE_H +#define _INTERFACE_IDLEMODE_H + +INT InterfaceIdleModeWakeup(struct bcm_mini_adapter *Adapter); + +INT InterfaceIdleModeRespond(struct bcm_mini_adapter *Adapter, + unsigned int *puiBuffer); + +VOID InterfaceWriteIdleModeWakePattern(struct bcm_mini_adapter *Adapter); + +INT InterfaceWakeUp(struct bcm_mini_adapter *Adapter); + +VOID InterfaceHandleShutdownModeWakeup(struct bcm_mini_adapter *Adapter); +#endif + diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c new file mode 100644 index 00000000000..7c04c73e3bc --- /dev/null +++ b/drivers/staging/bcm/InterfaceInit.c @@ -0,0 +1,717 @@ +#include "headers.h" +#include <linux/usb/ch9.h> +static struct usb_device_id InterfaceUsbtable[] = { + { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_SYM) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_226) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_326) }, + { } +}; +MODULE_DEVICE_TABLE(usb, InterfaceUsbtable); + +static int debug = -1; +module_param(debug, uint, 0600); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + +static const u32 default_msg = + NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK + | NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR + | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN; + +static int InterfaceAdapterInit(struct bcm_interface_adapter *Adapter); + +static void InterfaceAdapterFree(struct bcm_interface_adapter *psIntfAdapter) +{ + int i = 0; + + /* Wake up the wait_queue... */ + if (psIntfAdapter->psAdapter->LEDInfo.led_thread_running & + BCM_LED_THREAD_RUNNING_ACTIVELY) { + psIntfAdapter->psAdapter->DriverState = DRIVER_HALT; + wake_up(&psIntfAdapter->psAdapter->LEDInfo.notify_led_event); + } + reset_card_proc(psIntfAdapter->psAdapter); + + /* + * worst case time taken by the RDM/WRM will be 5 sec. will check after + * every 100 ms to accertain the device is not being accessed. After + * this No RDM/WRM should be made. + */ + while (psIntfAdapter->psAdapter->DeviceAccess) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, + DRV_ENTRY, DBG_LVL_ALL, + "Device is being accessed.\n"); + msleep(100); + } + /* Free interrupt URB */ + /* psIntfAdapter->psAdapter->device_removed = TRUE; */ + usb_free_urb(psIntfAdapter->psInterruptUrb); + + /* Free transmit URBs */ + for (i = 0; i < MAXIMUM_USB_TCB; i++) { + if (psIntfAdapter->asUsbTcb[i].urb != NULL) { + usb_free_urb(psIntfAdapter->asUsbTcb[i].urb); + psIntfAdapter->asUsbTcb[i].urb = NULL; + } + } + /* Free receive URB and buffers */ + for (i = 0; i < MAXIMUM_USB_RCB; i++) { + if (psIntfAdapter->asUsbRcb[i].urb != NULL) { + kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer); + usb_free_urb(psIntfAdapter->asUsbRcb[i].urb); + psIntfAdapter->asUsbRcb[i].urb = NULL; + } + } + AdapterFree(psIntfAdapter->psAdapter); +} + +static void ConfigureEndPointTypesThroughEEPROM(struct bcm_mini_adapter *Adapter) +{ + u32 ulReg; + int bytes; + struct bcm_interface_adapter *interfaceAdapter; + + /* Program EP2 MAX_PKT_SIZE */ + ulReg = ntohl(EP2_MPS_REG); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x128, 4, TRUE); + ulReg = ntohl(EP2_MPS); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x12C, 4, TRUE); + + ulReg = ntohl(EP2_CFG_REG); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x132, 4, TRUE); + interfaceAdapter = + (struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter); + if (interfaceAdapter->bHighSpeedDevice) { + ulReg = ntohl(EP2_CFG_INT); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE); + } else { + /* USE BULK EP as TX in FS mode. */ + ulReg = ntohl(EP2_CFG_BULK); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE); + } + + /* Program EP4 MAX_PKT_SIZE. */ + ulReg = ntohl(EP4_MPS_REG); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x13C, 4, TRUE); + ulReg = ntohl(EP4_MPS); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x140, 4, TRUE); + + /* Program TX EP as interrupt(Alternate Setting) */ + bytes = rdmalt(Adapter, 0x0F0110F8, &ulReg, sizeof(u32)); + if (bytes < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, "reading of Tx EP failed\n"); + return; + } + ulReg |= 0x6; + + ulReg = ntohl(ulReg); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1CC, 4, TRUE); + + ulReg = ntohl(EP4_CFG_REG); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C8, 4, TRUE); + /* Program ISOCHRONOUS EP size to zero. */ + ulReg = ntohl(ISO_MPS_REG); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D2, 4, TRUE); + ulReg = ntohl(ISO_MPS); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D6, 4, TRUE); + + /* + * Update EEPROM Version. + * Read 4 bytes from 508 and modify 511 and 510. + */ + ReadBeceemEEPROM(Adapter, 0x1FC, &ulReg); + ulReg &= 0x0101FFFF; + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1FC, 4, TRUE); + + /* Update length field if required. Also make the string NULL terminated. */ + + ReadBeceemEEPROM(Adapter, 0xA8, &ulReg); + if ((ulReg&0x00FF0000)>>16 > 0x30) { + ulReg = (ulReg&0xFF00FFFF)|(0x30<<16); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0xA8, 4, TRUE); + } + ReadBeceemEEPROM(Adapter, 0x148, &ulReg); + if ((ulReg&0x00FF0000)>>16 > 0x30) { + ulReg = (ulReg&0xFF00FFFF)|(0x30<<16); + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x148, 4, TRUE); + } + ulReg = 0; + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x122, 4, TRUE); + ulReg = 0; + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C2, 4, TRUE); +} + +static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + int retval; + struct bcm_mini_adapter *psAdapter; + struct bcm_interface_adapter *psIntfAdapter; + struct net_device *ndev; + + /* Reserve one extra queue for the bit-bucket */ + ndev = alloc_etherdev_mq(sizeof(struct bcm_mini_adapter), + NO_OF_QUEUES + 1); + if (ndev == NULL) { + dev_err(&udev->dev, DRV_NAME ": no memory for device\n"); + return -ENOMEM; + } + + SET_NETDEV_DEV(ndev, &intf->dev); + + psAdapter = netdev_priv(ndev); + psAdapter->dev = ndev; + psAdapter->msg_enable = netif_msg_init(debug, default_msg); + + /* Init default driver debug state */ + + psAdapter->stDebugState.debug_level = DBG_LVL_CURR; + psAdapter->stDebugState.type = DBG_TYPE_INITEXIT; + + /* + * Technically, one can start using BCM_DEBUG_PRINT after this point. + * However, realize that by default the Type/Subtype bitmaps are all + * zero now; so no prints will actually appear until the TestApp turns + * on debug paths via the ioctl(); so practically speaking, in early + * init, no logging happens. + * + * A solution (used below): we explicitly set the bitmaps to 1 for + * Type=DBG_TYPE_INITEXIT and ALL subtype's of the same. Now all bcm + * debug statements get logged, enabling debug during early init. + * Further, we turn this OFF once init_module() completes. + */ + + psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0xff; + BCM_SHOW_DEBUG_BITMAP(psAdapter); + + retval = InitAdapter(psAdapter); + if (retval) { + dev_err(&udev->dev, DRV_NAME ": InitAdapter Failed\n"); + AdapterFree(psAdapter); + return retval; + } + + /* Allocate interface adapter structure */ + psIntfAdapter = kzalloc(sizeof(struct bcm_interface_adapter), + GFP_KERNEL); + if (psIntfAdapter == NULL) { + AdapterFree(psAdapter); + return -ENOMEM; + } + + psAdapter->pvInterfaceAdapter = psIntfAdapter; + psIntfAdapter->psAdapter = psAdapter; + + /* Store usb interface in Interface Adapter */ + psIntfAdapter->interface = intf; + usb_set_intfdata(intf, psIntfAdapter); + + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL, + "psIntfAdapter 0x%p\n", psIntfAdapter); + retval = InterfaceAdapterInit(psIntfAdapter); + if (retval) { + /* If the Firmware/Cfg File is not present + * then return success, let the application + * download the files. + */ + if (-ENOENT == retval) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "File Not Found. Use app to download.\n"); + return STATUS_SUCCESS; + } + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, "InterfaceAdapterInit failed.\n"); + usb_set_intfdata(intf, NULL); + udev = interface_to_usbdev(intf); + usb_put_dev(udev); + InterfaceAdapterFree(psIntfAdapter); + return retval; + } + if (psAdapter->chip_id > T3) { + uint32_t uiNackZeroLengthInt = 4; + + retval = + wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, + &uiNackZeroLengthInt, + sizeof(uiNackZeroLengthInt)); + if (retval) + return retval; + } + + /* Check whether the USB-Device Supports remote Wake-Up */ + if (USB_CONFIG_ATT_WAKEUP & udev->actconfig->desc.bmAttributes) { + /* If Suspend then only support dynamic suspend */ + if (psAdapter->bDoSuspend) { +#ifdef CONFIG_PM + pm_runtime_set_autosuspend_delay(&udev->dev, 0); + intf->needs_remote_wakeup = 1; + usb_enable_autosuspend(udev); + device_init_wakeup(&intf->dev, 1); + INIT_WORK(&psIntfAdapter->usbSuspendWork, + putUsbSuspend); + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "Enabling USB Auto-Suspend\n"); +#endif + } else { + intf->needs_remote_wakeup = 0; + usb_disable_autosuspend(udev); + } + } + + psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0x0; + return retval; +} + +static void usbbcm_disconnect(struct usb_interface *intf) +{ + struct bcm_interface_adapter *psIntfAdapter = usb_get_intfdata(intf); + struct bcm_mini_adapter *psAdapter; + struct usb_device *udev = interface_to_usbdev(intf); + + if (psIntfAdapter == NULL) + return; + + psAdapter = psIntfAdapter->psAdapter; + netif_device_detach(psAdapter->dev); + + if (psAdapter->bDoSuspend) + intf->needs_remote_wakeup = 0; + + psAdapter->device_removed = TRUE; + usb_set_intfdata(intf, NULL); + InterfaceAdapterFree(psIntfAdapter); + usb_put_dev(udev); +} + +static int AllocUsbCb(struct bcm_interface_adapter *psIntfAdapter) +{ + int i = 0; + + for (i = 0; i < MAXIMUM_USB_TCB; i++) { + psIntfAdapter->asUsbTcb[i].urb = usb_alloc_urb(0, GFP_KERNEL); + + if (psIntfAdapter->asUsbTcb[i].urb == NULL) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_PRINTK, 0, 0, + "Can't allocate Tx urb for index %d\n", + i); + return -ENOMEM; + } + } + + for (i = 0; i < MAXIMUM_USB_RCB; i++) { + psIntfAdapter->asUsbRcb[i].urb = usb_alloc_urb(0, GFP_KERNEL); + + if (psIntfAdapter->asUsbRcb[i].urb == NULL) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_PRINTK, 0, 0, + "Can't allocate Rx urb for index %d\n", + i); + return -ENOMEM; + } + + psIntfAdapter->asUsbRcb[i].urb->transfer_buffer = + kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL); + + if (psIntfAdapter->asUsbRcb[i].urb->transfer_buffer == NULL) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_PRINTK, 0, 0, + "Can't allocate Rx buffer for index %d\n", + i); + return -ENOMEM; + } + psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length = + MAX_DATA_BUFFER_SIZE; + } + return 0; +} + +static int device_run(struct bcm_interface_adapter *psIntfAdapter) +{ + int value = 0; + UINT status = STATUS_SUCCESS; + + status = InitCardAndDownloadFirmware(psIntfAdapter->psAdapter); + if (status != STATUS_SUCCESS) { + pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n"); + return status; + } + if (psIntfAdapter->psAdapter->fw_download_done) { + if (StartInterruptUrb(psIntfAdapter)) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "Cannot send interrupt in URB\n"); + } + + /* + * now register the cntrl interface. after downloading the f/w + * waiting for 5 sec to get the mailbox interrupt. + */ + psIntfAdapter->psAdapter->waiting_to_fw_download_done = false; + value = wait_event_timeout( + psIntfAdapter->psAdapter->ioctl_fw_dnld_wait_queue, + psIntfAdapter->psAdapter->waiting_to_fw_download_done, + 5 * HZ); + + if (value == 0) + pr_err(DRV_NAME ": Timeout waiting for mailbox interrupt.\n"); + + if (register_control_device_interface( + psIntfAdapter->psAdapter) < 0) { + pr_err(DRV_NAME ": Register Control Device failed.\n"); + return -EIO; + } + } + return 0; +} + +static int InterfaceAdapterInit(struct bcm_interface_adapter *psIntfAdapter) +{ + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + size_t buffer_size; + unsigned long value; + int retval = 0; + int usedIntOutForBulkTransfer = 0; + bool bBcm16 = false; + UINT uiData = 0; + int bytes; + + /* Store the usb dev into interface adapter */ + psIntfAdapter->udev = + usb_get_dev(interface_to_usbdev(psIntfAdapter->interface)); + + psIntfAdapter->bHighSpeedDevice = + (psIntfAdapter->udev->speed == USB_SPEED_HIGH); + psIntfAdapter->psAdapter->interface_rdm = BcmRDM; + psIntfAdapter->psAdapter->interface_wrm = BcmWRM; + + bytes = rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG, + (u32 *) &(psIntfAdapter->psAdapter->chip_id), + sizeof(u32)); + if (bytes < 0) { + retval = bytes; + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, + "CHIP ID Read Failed\n"); + return retval; + } + + if (0xbece3200 == (psIntfAdapter->psAdapter->chip_id & ~(0xF0))) + psIntfAdapter->psAdapter->chip_id &= ~0xF0; + + dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n", + psIntfAdapter->psAdapter->chip_id); + + iface_desc = psIntfAdapter->interface->cur_altsetting; + + if (psIntfAdapter->psAdapter->chip_id == T3B) { + /* T3B device will have EEPROM, check if EEPROM is proper and + * BCM16 can be done or not. */ + BeceemEEPROMBulkRead(psIntfAdapter->psAdapter, &uiData, 0x0, 4); + if (uiData == BECM) + bBcm16 = TRUE; + + dev_info(&psIntfAdapter->udev->dev, + "number of alternate setting %d\n", + psIntfAdapter->interface->num_altsetting); + + if (bBcm16 == TRUE) { + /* selecting alternate setting one as a default setting + * for High Speed modem. */ + if (psIntfAdapter->bHighSpeedDevice) + retval = usb_set_interface(psIntfAdapter->udev, + DEFAULT_SETTING_0, + ALTERNATE_SETTING_1); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "BCM16 is applicable on this dongle\n"); + if (retval || !psIntfAdapter->bHighSpeedDevice) { + usedIntOutForBulkTransfer = EP2; + endpoint = &iface_desc->endpoint[EP2].desc; + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n"); + /* + * If Modem is high speed device EP2 should be + * INT OUT End point + * + * If Mode is FS then EP2 should be bulk end + * point + */ + if ((psIntfAdapter->bHighSpeedDevice && + !usb_endpoint_is_int_out(endpoint)) || + (!psIntfAdapter->bHighSpeedDevice && + !usb_endpoint_is_bulk_out(endpoint))) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, + DRV_ENTRY, DBG_LVL_ALL, + "Configuring the EEPROM\n"); + /* change the EP2, EP4 to INT OUT end point */ + ConfigureEndPointTypesThroughEEPROM( + psIntfAdapter->psAdapter); + + /* + * It resets the device and if any thing + * gets changed in USB descriptor it + * will show fail and re-enumerate the + * device + */ + retval = usb_reset_device( + psIntfAdapter->udev); + if (retval) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, + DRV_ENTRY, + DBG_LVL_ALL, + "reset failed. Re-enumerating the device.\n"); + return retval; + } + + } + if (!psIntfAdapter->bHighSpeedDevice && + usb_endpoint_is_bulk_out(endpoint)) { + /* Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail. */ + UINT _uiData = ntohl(EP2_CFG_INT); + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, + DRV_ENTRY, DBG_LVL_ALL, + "Reverting Bulk to INT as it is in Full Speed mode.\n"); + BeceemEEPROMBulkWrite( + psIntfAdapter->psAdapter, + (PUCHAR) & _uiData, + 0x136, 4, TRUE); + } + } else { + usedIntOutForBulkTransfer = EP4; + endpoint = &iface_desc->endpoint[EP4].desc; + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "Choosing AltSetting as a default setting.\n"); + if (!usb_endpoint_is_int_out(endpoint)) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, + DRV_ENTRY, DBG_LVL_ALL, + "Dongle does not have BCM16 Fix.\n"); + /* change the EP2, EP4 to INT OUT end point and use EP4 in altsetting */ + ConfigureEndPointTypesThroughEEPROM( + psIntfAdapter->psAdapter); + + /* + * It resets the device and if any thing + * gets changed in USB descriptor it + * will show fail and re-enumerate the + * device + */ + retval = usb_reset_device( + psIntfAdapter->udev); + if (retval) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, + DRV_ENTRY, + DBG_LVL_ALL, + "reset failed. Re-enumerating the device.\n"); + return retval; + } + + } + } + } + } + + iface_desc = psIntfAdapter->interface->cur_altsetting; + + for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) { + endpoint = &iface_desc->endpoint[value].desc; + + if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && + usb_endpoint_is_bulk_in(endpoint)) { + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + psIntfAdapter->sBulkIn.bulk_in_size = buffer_size; + psIntfAdapter->sBulkIn.bulk_in_endpointAddr = + endpoint->bEndpointAddress; + psIntfAdapter->sBulkIn.bulk_in_pipe = usb_rcvbulkpipe( + psIntfAdapter->udev, + psIntfAdapter->sBulkIn.bulk_in_endpointAddr); + } + + if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && + usb_endpoint_is_bulk_out(endpoint)) { + psIntfAdapter->sBulkOut.bulk_out_endpointAddr = + endpoint->bEndpointAddress; + psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndbulkpipe( + psIntfAdapter->udev, + psIntfAdapter->sBulkOut.bulk_out_endpointAddr); + } + + if (!psIntfAdapter->sIntrIn.int_in_endpointAddr && + usb_endpoint_is_int_in(endpoint)) { + buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); + psIntfAdapter->sIntrIn.int_in_size = buffer_size; + psIntfAdapter->sIntrIn.int_in_endpointAddr = + endpoint->bEndpointAddress; + psIntfAdapter->sIntrIn.int_in_interval = + endpoint->bInterval; + psIntfAdapter->sIntrIn.int_in_buffer = + kmalloc(buffer_size, GFP_KERNEL); + if (!psIntfAdapter->sIntrIn.int_in_buffer) + return -EINVAL; + } + + if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && + usb_endpoint_is_int_out(endpoint)) { + if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && + (psIntfAdapter->psAdapter->chip_id == T3B) && + (value == usedIntOutForBulkTransfer)) { + /* use first intout end point as a bulk out end point */ + buffer_size = + le16_to_cpu(endpoint->wMaxPacketSize); + psIntfAdapter->sBulkOut.bulk_out_size = + buffer_size; + psIntfAdapter->sBulkOut.bulk_out_endpointAddr = + endpoint->bEndpointAddress; + psIntfAdapter->sBulkOut.bulk_out_pipe = + usb_sndintpipe(psIntfAdapter->udev, + psIntfAdapter->sBulkOut + .bulk_out_endpointAddr); + psIntfAdapter->sBulkOut.int_out_interval = + endpoint->bInterval; + } else if (value == EP6) { + buffer_size = + le16_to_cpu(endpoint->wMaxPacketSize); + psIntfAdapter->sIntrOut.int_out_size = + buffer_size; + psIntfAdapter->sIntrOut.int_out_endpointAddr = + endpoint->bEndpointAddress; + psIntfAdapter->sIntrOut.int_out_interval = + endpoint->bInterval; + psIntfAdapter->sIntrOut.int_out_buffer = + kmalloc(buffer_size, GFP_KERNEL); + if (!psIntfAdapter->sIntrOut.int_out_buffer) + return -EINVAL; + } + } + } + + usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter); + + psIntfAdapter->psAdapter->bcm_file_download = InterfaceFileDownload; + psIntfAdapter->psAdapter->bcm_file_readback_from_chip = + InterfaceFileReadbackFromChip; + psIntfAdapter->psAdapter->interface_transmit = InterfaceTransmitPacket; + + retval = CreateInterruptUrb(psIntfAdapter); + + if (retval) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, + "Cannot create interrupt urb\n"); + return retval; + } + + retval = AllocUsbCb(psIntfAdapter); + if (retval) + return retval; + + return device_run(psIntfAdapter); +} + +static int InterfaceSuspend(struct usb_interface *intf, pm_message_t message) +{ + struct bcm_interface_adapter *psIntfAdapter = usb_get_intfdata(intf); + + psIntfAdapter->bSuspended = TRUE; + + if (psIntfAdapter->bPreparingForBusSuspend) { + psIntfAdapter->bPreparingForBusSuspend = false; + + if (psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE) { + psIntfAdapter->psAdapter->IdleMode = TRUE; + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "Host Entered in PMU Idle Mode.\n"); + } else { + psIntfAdapter->psAdapter->bShutStatus = TRUE; + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_INITEXIT, DRV_ENTRY, + DBG_LVL_ALL, + "Host Entered in PMU Shutdown Mode.\n"); + } + } + psIntfAdapter->psAdapter->bPreparingForLowPowerMode = false; + + /* Signaling the control pkt path */ + wake_up(&psIntfAdapter->psAdapter->lowpower_mode_wait_queue); + + return 0; +} + +static int InterfaceResume(struct usb_interface *intf) +{ + struct bcm_interface_adapter *psIntfAdapter = usb_get_intfdata(intf); + + mdelay(100); + psIntfAdapter->bSuspended = false; + + StartInterruptUrb(psIntfAdapter); + InterfaceRx(psIntfAdapter); + return 0; +} + +static struct usb_driver usbbcm_driver = { + .name = "usbbcm", + .probe = usbbcm_device_probe, + .disconnect = usbbcm_disconnect, + .suspend = InterfaceSuspend, + .resume = InterfaceResume, + .id_table = InterfaceUsbtable, + .supports_autosuspend = 1, +}; + +struct class *bcm_class; + +static __init int bcm_init(void) +{ + int retval; + + pr_info("%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION); + pr_info("%s\n", DRV_COPYRIGHT); + + bcm_class = class_create(THIS_MODULE, DRV_NAME); + if (IS_ERR(bcm_class)) { + pr_err(DRV_NAME ": could not create class\n"); + return PTR_ERR(bcm_class); + } + + retval = usb_register(&usbbcm_driver); + if (retval < 0) { + pr_err(DRV_NAME ": could not register usb driver\n"); + class_destroy(bcm_class); + return retval; + } + return 0; +} + +static __exit void bcm_exit(void) +{ + usb_deregister(&usbbcm_driver); + class_destroy(bcm_class); +} + +module_init(bcm_init); +module_exit(bcm_exit); + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/bcm/InterfaceInit.h b/drivers/staging/bcm/InterfaceInit.h new file mode 100644 index 00000000000..ffa6e9667ec --- /dev/null +++ b/drivers/staging/bcm/InterfaceInit.h @@ -0,0 +1,26 @@ +#ifndef _INTERFACE_INIT_H +#define _INTERFACE_INIT_H + +#define BCM_USB_VENDOR_ID_T3 0x198f +#define BCM_USB_VENDOR_ID_FOXCONN 0x0489 +#define BCM_USB_VENDOR_ID_ZTE 0x19d2 + +#define BCM_USB_PRODUCT_ID_T3 0x0300 +#define BCM_USB_PRODUCT_ID_T3B 0x0210 +#define BCM_USB_PRODUCT_ID_T3L 0x0220 +#define BCM_USB_PRODUCT_ID_SYM 0x15E +#define BCM_USB_PRODUCT_ID_1901 0xe017 +#define BCM_USB_PRODUCT_ID_226 0x0132 /* not sure if this is valid */ +#define BCM_USB_PRODUCT_ID_ZTE_226 0x172 +#define BCM_USB_PRODUCT_ID_ZTE_326 0x173 /* ZTE AX326 */ +#define BCM_USB_PRODUCT_ID_ZTE_TU25 0x0007 + +#define BCM_USB_MINOR_BASE 192 + +int InterfaceInitialize(void); + +int InterfaceExit(void); + +int usbbcm_worker_thread(struct bcm_interface_adapter *psIntfAdapter); + +#endif diff --git a/drivers/staging/bcm/InterfaceIsr.c b/drivers/staging/bcm/InterfaceIsr.c new file mode 100644 index 00000000000..b9f8a7aa24f --- /dev/null +++ b/drivers/staging/bcm/InterfaceIsr.c @@ -0,0 +1,190 @@ +#include "headers.h" + + +static void read_int_callback(struct urb *urb/*, struct pt_regs *regs*/) +{ + int status = urb->status; + struct bcm_interface_adapter *psIntfAdapter = + (struct bcm_interface_adapter *)urb->context; + struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter; + + if (netif_msg_intr(Adapter)) + pr_info(PFX "%s: interrupt status %d\n", + Adapter->dev->name, status); + + if (Adapter->device_removed) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, "Device has Got Removed."); + return; + } + + if ((Adapter->bPreparingForLowPowerMode && Adapter->bDoSuspend) || + psIntfAdapter->bSuspended || + psIntfAdapter->bPreparingForBusSuspend) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, + "Interrupt call back is called while suspending the device"); + return; + } + + switch (status) { + /* success */ + case STATUS_SUCCESS: + if (urb->actual_length) { + + if (psIntfAdapter->ulInterruptData[1] & 0xFF) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + INTF_INIT, DBG_LVL_ALL, + "Got USIM interrupt"); + } + + if (psIntfAdapter->ulInterruptData[1] & 0xFF00) { + atomic_set(&Adapter->CurrNumFreeTxDesc, + (psIntfAdapter->ulInterruptData[1] & + 0xFF00) >> 8); + atomic_set(&Adapter->uiMBupdate, TRUE); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + INTF_INIT, DBG_LVL_ALL, + "TX mailbox contains %d", + atomic_read(&Adapter->CurrNumFreeTxDesc)); + } + if (psIntfAdapter->ulInterruptData[1] >> 16) { + Adapter->CurrNumRecvDescs = + (psIntfAdapter->ulInterruptData[1] >> 16); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + INTF_INIT, DBG_LVL_ALL, + "RX mailbox contains %d", + Adapter->CurrNumRecvDescs); + InterfaceRx(psIntfAdapter); + } + if (Adapter->fw_download_done && + !Adapter->downloadDDR && + atomic_read(&Adapter->CurrNumFreeTxDesc)) { + + psIntfAdapter->psAdapter->downloadDDR += 1; + wake_up(&Adapter->tx_packet_wait_queue); + } + if (!Adapter->waiting_to_fw_download_done) { + Adapter->waiting_to_fw_download_done = TRUE; + wake_up(&Adapter->ioctl_fw_dnld_wait_queue); + } + if (!atomic_read(&Adapter->TxPktAvail)) { + atomic_set(&Adapter->TxPktAvail, 1); + wake_up(&Adapter->tx_packet_wait_queue); + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, "Firing interrupt in URB"); + } + break; + case -ENOENT: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, "URB has got disconnected...."); + return; + case -EINPROGRESS: + /* + * This situation may happened when URBunlink is used. for + * detail check usb_unlink_urb documentation. + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, + "Impossibe condition has occurred... something very bad is going on"); + break; + /* return; */ + case -EPIPE: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, + "Interrupt IN endPoint has got halted/stalled...need to clear this"); + Adapter->bEndPointHalted = TRUE; + wake_up(&Adapter->tx_packet_wait_queue); + urb->status = STATUS_SUCCESS; + return; + /* software-driven interface shutdown */ + case -ECONNRESET: /* URB got unlinked */ + case -ESHUTDOWN: /* hardware gone. this is the serious problem */ + /* + * Occurs only when something happens with the + * host controller device + */ + case -ENODEV: /* Device got removed */ + case -EINVAL: + /* + * Some thing very bad happened with the URB. No + * description is available. + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, "interrupt urb error %d", status); + urb->status = STATUS_SUCCESS; + break; + /* return; */ + default: + /* + * This is required to check what is the defaults conditions + * when it occurs.. + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, + "GOT DEFAULT INTERRUPT URB STATUS :%d..Please Analyze it...", + status); + break; + } + + StartInterruptUrb(psIntfAdapter); + + +} + +int CreateInterruptUrb(struct bcm_interface_adapter *psIntfAdapter) +{ + psIntfAdapter->psInterruptUrb = usb_alloc_urb(0, GFP_KERNEL); + if (!psIntfAdapter->psInterruptUrb) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, + INTF_INIT, DBG_LVL_ALL, + "Cannot allocate interrupt urb"); + return -ENOMEM; + } + psIntfAdapter->psInterruptUrb->transfer_buffer = + psIntfAdapter->ulInterruptData; + psIntfAdapter->psInterruptUrb->transfer_buffer_length = + sizeof(psIntfAdapter->ulInterruptData); + + psIntfAdapter->sIntrIn.int_in_pipe = usb_rcvintpipe(psIntfAdapter->udev, + psIntfAdapter->sIntrIn.int_in_endpointAddr); + + usb_fill_int_urb(psIntfAdapter->psInterruptUrb, psIntfAdapter->udev, + psIntfAdapter->sIntrIn.int_in_pipe, + psIntfAdapter->psInterruptUrb->transfer_buffer, + psIntfAdapter->psInterruptUrb->transfer_buffer_length, + read_int_callback, psIntfAdapter, + psIntfAdapter->sIntrIn.int_in_interval); + + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, INTF_INIT, + DBG_LVL_ALL, "Interrupt Interval: %d\n", + psIntfAdapter->sIntrIn.int_in_interval); + return 0; +} + + +INT StartInterruptUrb(struct bcm_interface_adapter *psIntfAdapter) +{ + INT status = 0; + + if (!(psIntfAdapter->psAdapter->device_removed || + psIntfAdapter->psAdapter->bEndPointHalted || + psIntfAdapter->bSuspended || + psIntfAdapter->bPreparingForBusSuspend || + psIntfAdapter->psAdapter->StopAllXaction)) { + status = + usb_submit_urb(psIntfAdapter->psInterruptUrb, GFP_ATOMIC); + if (status) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, + DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL, + "Cannot send inturb %d\n", status); + if (status == -EPIPE) { + psIntfAdapter->psAdapter->bEndPointHalted = + TRUE; + wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue); + } + } + } + return status; +} + diff --git a/drivers/staging/bcm/InterfaceIsr.h b/drivers/staging/bcm/InterfaceIsr.h new file mode 100644 index 00000000000..3073bd71cfe --- /dev/null +++ b/drivers/staging/bcm/InterfaceIsr.h @@ -0,0 +1,15 @@ +#ifndef _INTERFACE_ISR_H +#define _INTERFACE_ISR_H + +int CreateInterruptUrb(struct bcm_interface_adapter *psIntfAdapter); + + +INT StartInterruptUrb(struct bcm_interface_adapter *psIntfAdapter); + + +VOID InterfaceEnableInterrupt(struct bcm_mini_adapter *Adapter); + +VOID InterfaceDisableInterrupt(struct bcm_mini_adapter *Adapter); + +#endif + diff --git a/drivers/staging/bcm/InterfaceMacros.h b/drivers/staging/bcm/InterfaceMacros.h new file mode 100644 index 00000000000..7001caff9e2 --- /dev/null +++ b/drivers/staging/bcm/InterfaceMacros.h @@ -0,0 +1,18 @@ +#ifndef _INTERFACE_MACROS_H +#define _INTERFACE_MACROS_H + +#define BCM_USB_MAX_READ_LENGTH 2048 + +#define MAXIMUM_USB_TCB 128 +#define MAXIMUM_USB_RCB 128 + +#define MAX_BUFFERS_PER_QUEUE 256 + +#define MAX_DATA_BUFFER_SIZE 2048 + +//Num of Asynchronous reads pending +#define NUM_RX_DESC 64 + +#define SYS_CFG 0x0F000C00 + +#endif diff --git a/drivers/staging/bcm/InterfaceMisc.c b/drivers/staging/bcm/InterfaceMisc.c new file mode 100644 index 00000000000..4173fd7d671 --- /dev/null +++ b/drivers/staging/bcm/InterfaceMisc.c @@ -0,0 +1,217 @@ +#include "headers.h" + +int InterfaceRDM(struct bcm_interface_adapter *psIntfAdapter, + unsigned int addr, + void *buff, + int len) +{ + int bytes; + + if (!psIntfAdapter) + return -EINVAL; + + if (psIntfAdapter->psAdapter->device_removed == TRUE) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Device got removed"); + return -ENODEV; + } + + if ((psIntfAdapter->psAdapter->StopAllXaction == TRUE) && (psIntfAdapter->psAdapter->chip_id >= T3LPB)) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM, DBG_LVL_ALL, "Currently Xaction is not allowed on the bus"); + return -EACCES; + } + + if (psIntfAdapter->bSuspended == TRUE || psIntfAdapter->bPreparingForBusSuspend == TRUE) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM, DBG_LVL_ALL, "Bus is in suspended states hence RDM not allowed.."); + return -EACCES; + } + psIntfAdapter->psAdapter->DeviceAccess = TRUE; + + bytes = usb_control_msg(psIntfAdapter->udev, + usb_rcvctrlpipe(psIntfAdapter->udev, 0), + 0x02, + 0xC2, + (addr & 0xFFFF), + ((addr >> 16) & 0xFFFF), + buff, + len, + 5000); + + if (-ENODEV == bytes) + psIntfAdapter->psAdapter->device_removed = TRUE; + + if (bytes < 0) + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM, DBG_LVL_ALL, "RDM failed status :%d", bytes); + else + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, RDM, DBG_LVL_ALL, "RDM sent %d", bytes); + + psIntfAdapter->psAdapter->DeviceAccess = false; + return bytes; +} + +int InterfaceWRM(struct bcm_interface_adapter *psIntfAdapter, + unsigned int addr, + void *buff, + int len) +{ + int retval = 0; + + if (!psIntfAdapter) + return -EINVAL; + + if (psIntfAdapter->psAdapter->device_removed == TRUE) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Device got removed"); + return -ENODEV; + } + + if ((psIntfAdapter->psAdapter->StopAllXaction == TRUE) && (psIntfAdapter->psAdapter->chip_id >= T3LPB)) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, WRM, DBG_LVL_ALL, "Currently Xaction is not allowed on the bus..."); + return -EACCES; + } + + if (psIntfAdapter->bSuspended == TRUE || psIntfAdapter->bPreparingForBusSuspend == TRUE) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, WRM, DBG_LVL_ALL, "Bus is in suspended states hence RDM not allowed.."); + return -EACCES; + } + + psIntfAdapter->psAdapter->DeviceAccess = TRUE; + + retval = usb_control_msg(psIntfAdapter->udev, + usb_sndctrlpipe(psIntfAdapter->udev, 0), + 0x01, + 0x42, + (addr & 0xFFFF), + ((addr >> 16) & 0xFFFF), + buff, + len, + 5000); + + if (-ENODEV == retval) + psIntfAdapter->psAdapter->device_removed = TRUE; + + if (retval < 0) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, WRM, DBG_LVL_ALL, "WRM failed status :%d", retval); + psIntfAdapter->psAdapter->DeviceAccess = false; + return retval; + } else { + psIntfAdapter->psAdapter->DeviceAccess = false; + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_OTHERS, WRM, DBG_LVL_ALL, "WRM sent %d", retval); + return STATUS_SUCCESS; + } +} + +int BcmRDM(void *arg, + unsigned int addr, + void *buff, + int len) +{ + return InterfaceRDM((struct bcm_interface_adapter *)arg, addr, buff, len); +} + +int BcmWRM(void *arg, + unsigned int addr, + void *buff, + int len) +{ + return InterfaceWRM((struct bcm_interface_adapter *)arg, addr, buff, len); +} + +int Bcm_clear_halt_of_endpoints(struct bcm_mini_adapter *Adapter) +{ + struct bcm_interface_adapter *psIntfAdapter = (struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter); + int status = STATUS_SUCCESS; + + /* + * usb_clear_halt - tells device to clear endpoint halt/stall condition + * @dev: device whose endpoint is halted + * @pipe: endpoint "pipe" being cleared + * @ Context: !in_interrupt () + * + * usb_clear_halt is the synchrnous call and returns 0 on success else returns with error code. + * This is used to clear halt conditions for bulk and interrupt endpoints only. + * Control and isochronous endpoints never halts. + * + * Any URBs queued for such an endpoint should normally be unlinked by the driver + * before clearing the halt condition. + * + */ + + /* Killing all the submitted urbs to different end points. */ + Bcm_kill_all_URBs(psIntfAdapter); + + /* clear the halted/stalled state for every end point */ + status = usb_clear_halt(psIntfAdapter->udev, psIntfAdapter->sIntrIn.int_in_pipe); + if (status != STATUS_SUCCESS) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL, "Unable to Clear Halt of Interrupt IN end point. :%d ", status); + + status = usb_clear_halt(psIntfAdapter->udev, psIntfAdapter->sBulkIn.bulk_in_pipe); + if (status != STATUS_SUCCESS) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL, "Unable to Clear Halt of Bulk IN end point. :%d ", status); + + status = usb_clear_halt(psIntfAdapter->udev, psIntfAdapter->sBulkOut.bulk_out_pipe); + if (status != STATUS_SUCCESS) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, INTF_INIT, DBG_LVL_ALL, "Unable to Clear Halt of Bulk OUT end point. :%d ", status); + + return status; +} + +void Bcm_kill_all_URBs(struct bcm_interface_adapter *psIntfAdapter) +{ + struct urb *tempUrb = NULL; + unsigned int i; + + /* + * usb_kill_urb - cancel a transfer request and wait for it to finish + * @urb: pointer to URB describing a previously submitted request, + * returns nothing as it is void returned API. + * + * This routine cancels an in-progress request. It is guaranteed that + * upon return all completion handlers will have finished and the URB + * will be totally idle and available for reuse + * + * This routine may not be used in an interrupt context (such as a bottom + * half or a completion handler), or when holding a spinlock, or in other + * situations where the caller can't schedule(). + * + */ + + /* Cancel submitted Interrupt-URB's */ + if (psIntfAdapter->psInterruptUrb) { + if (psIntfAdapter->psInterruptUrb->status == -EINPROGRESS) + usb_kill_urb(psIntfAdapter->psInterruptUrb); + } + + /* Cancel All submitted TX URB's */ + for (i = 0; i < MAXIMUM_USB_TCB; i++) { + tempUrb = psIntfAdapter->asUsbTcb[i].urb; + if (tempUrb) { + if (tempUrb->status == -EINPROGRESS) + usb_kill_urb(tempUrb); + } + } + + for (i = 0; i < MAXIMUM_USB_RCB; i++) { + tempUrb = psIntfAdapter->asUsbRcb[i].urb; + if (tempUrb) { + if (tempUrb->status == -EINPROGRESS) + usb_kill_urb(tempUrb); + } + } + + atomic_set(&psIntfAdapter->uNumTcbUsed, 0); + atomic_set(&psIntfAdapter->uCurrTcb, 0); + + atomic_set(&psIntfAdapter->uNumRcbUsed, 0); + atomic_set(&psIntfAdapter->uCurrRcb, 0); +} + +void putUsbSuspend(struct work_struct *work) +{ + struct bcm_interface_adapter *psIntfAdapter = NULL; + struct usb_interface *intf = NULL; + psIntfAdapter = container_of(work, struct bcm_interface_adapter, usbSuspendWork); + intf = psIntfAdapter->interface; + + if (psIntfAdapter->bSuspended == false) + usb_autopm_put_interface(intf); +} + diff --git a/drivers/staging/bcm/InterfaceMisc.h b/drivers/staging/bcm/InterfaceMisc.h new file mode 100644 index 00000000000..efb68604615 --- /dev/null +++ b/drivers/staging/bcm/InterfaceMisc.h @@ -0,0 +1,42 @@ +#ifndef __INTERFACE_MISC_H +#define __INTERFACE_MISC_H + +INT +InterfaceRDM(struct bcm_interface_adapter *psIntfAdapter, + UINT addr, + PVOID buff, + INT len); + +INT +InterfaceWRM(struct bcm_interface_adapter *psIntfAdapter, + UINT addr, + PVOID buff, + INT len); + + +int InterfaceFileDownload(PVOID psIntfAdapter, + struct file *flp, + unsigned int on_chip_loc); + +int InterfaceFileReadbackFromChip(PVOID psIntfAdapter, + struct file *flp, + unsigned int on_chip_loc); + + +int BcmRDM(PVOID arg, + UINT addr, + PVOID buff, + INT len); + +int BcmWRM(PVOID arg, + UINT addr, + PVOID buff, + INT len); + +INT Bcm_clear_halt_of_endpoints(struct bcm_mini_adapter *Adapter); + +VOID Bcm_kill_all_URBs(struct bcm_interface_adapter *psIntfAdapter); + +#define DISABLE_USB_ZERO_LEN_INT 0x0F011878 + +#endif // __INTERFACE_MISC_H diff --git a/drivers/staging/bcm/InterfaceRx.c b/drivers/staging/bcm/InterfaceRx.c new file mode 100644 index 00000000000..11008173f91 --- /dev/null +++ b/drivers/staging/bcm/InterfaceRx.c @@ -0,0 +1,233 @@ +#include "headers.h" + +static int SearchVcid(struct bcm_mini_adapter *Adapter, unsigned short usVcid) +{ + int iIndex = 0; + + for (iIndex = (NO_OF_QUEUES-1); iIndex >= 0; iIndex--) + if (Adapter->PackInfo[iIndex].usVCID_Value == usVcid) + return iIndex; + return NO_OF_QUEUES+1; + +} + + +static struct bcm_usb_rcb * +GetBulkInRcb(struct bcm_interface_adapter *psIntfAdapter) +{ + struct bcm_usb_rcb *pRcb = NULL; + UINT index = 0; + + if ((atomic_read(&psIntfAdapter->uNumRcbUsed) < MAXIMUM_USB_RCB) && + (psIntfAdapter->psAdapter->StopAllXaction == false)) { + index = atomic_read(&psIntfAdapter->uCurrRcb); + pRcb = &psIntfAdapter->asUsbRcb[index]; + pRcb->bUsed = TRUE; + pRcb->psIntfAdapter = psIntfAdapter; + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Got Rx desc %d used %d", + index, atomic_read(&psIntfAdapter->uNumRcbUsed)); + index = (index + 1) % MAXIMUM_USB_RCB; + atomic_set(&psIntfAdapter->uCurrRcb, index); + atomic_inc(&psIntfAdapter->uNumRcbUsed); + } + return pRcb; +} + +/*this is receive call back - when pkt available for receive (BULK IN- end point)*/ +static void read_bulk_callback(struct urb *urb) +{ + struct sk_buff *skb = NULL; + bool bHeaderSupressionEnabled = false; + int QueueIndex = NO_OF_QUEUES + 1; + UINT uiIndex = 0; + int process_done = 1; + struct bcm_usb_rcb *pRcb = (struct bcm_usb_rcb *)urb->context; + struct bcm_interface_adapter *psIntfAdapter = pRcb->psIntfAdapter; + struct bcm_mini_adapter *Adapter = psIntfAdapter->psAdapter; + struct bcm_leader *pLeader = urb->transfer_buffer; + + if (unlikely(netif_msg_rx_status(Adapter))) + pr_info(PFX "%s: rx urb status %d length %d\n", + Adapter->dev->name, urb->status, urb->actual_length); + + if ((Adapter->device_removed == TRUE) || + (TRUE == Adapter->bEndPointHalted) || + (0 == urb->actual_length)) { + pRcb->bUsed = false; + atomic_dec(&psIntfAdapter->uNumRcbUsed); + return; + } + + if (urb->status != STATUS_SUCCESS) { + if (urb->status == -EPIPE) { + Adapter->bEndPointHalted = TRUE; + wake_up(&Adapter->tx_packet_wait_queue); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Rx URB has got cancelled. status :%d", urb->status); + } + pRcb->bUsed = false; + atomic_dec(&psIntfAdapter->uNumRcbUsed); + urb->status = STATUS_SUCCESS; + return; + } + + if (Adapter->bDoSuspend && (Adapter->bPreparingForLowPowerMode)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "device is going in low power mode while PMU option selected..hence rx packet should not be process"); + return; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Read back done len %d\n", pLeader->PLength); + if (!pLeader->PLength) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Leader Length 0"); + atomic_dec(&psIntfAdapter->uNumRcbUsed); + return; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "Leader Status:0x%hX, Length:0x%hX, VCID:0x%hX", pLeader->Status, pLeader->PLength, pLeader->Vcid); + if (MAX_CNTL_PKT_SIZE < pLeader->PLength) { + if (netif_msg_rx_err(Adapter)) + pr_info(PFX "%s: corrupted leader length...%d\n", + Adapter->dev->name, pLeader->PLength); + ++Adapter->dev->stats.rx_dropped; + atomic_dec(&psIntfAdapter->uNumRcbUsed); + return; + } + + QueueIndex = SearchVcid(Adapter, pLeader->Vcid); + if (QueueIndex < NO_OF_QUEUES) { + bHeaderSupressionEnabled = + Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled; + bHeaderSupressionEnabled = + bHeaderSupressionEnabled & Adapter->bPHSEnabled; + } + + skb = dev_alloc_skb(pLeader->PLength + SKB_RESERVE_PHS_BYTES + SKB_RESERVE_ETHERNET_HEADER); + if (!skb) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "NO SKBUFF!!! Dropping the Packet"); + atomic_dec(&psIntfAdapter->uNumRcbUsed); + return; + } + /* If it is a control Packet, then call handle_bcm_packet ()*/ + if ((ntohs(pLeader->Vcid) == VCID_CONTROL_PACKET) || + (!(pLeader->Status >= 0x20 && pLeader->Status <= 0x3F))) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_CTRL, DBG_LVL_ALL, "Received control pkt..."); + *(PUSHORT)skb->data = pLeader->Status; + memcpy(skb->data+sizeof(USHORT), urb->transfer_buffer + + (sizeof(struct bcm_leader)), pLeader->PLength); + skb->len = pLeader->PLength + sizeof(USHORT); + + spin_lock(&Adapter->control_queue_lock); + ENQUEUEPACKET(Adapter->RxControlHead, Adapter->RxControlTail, skb); + spin_unlock(&Adapter->control_queue_lock); + + atomic_inc(&Adapter->cntrlpktCnt); + wake_up(&Adapter->process_rx_cntrlpkt); + } else { + /* + * Data Packet, Format a proper Ethernet Header + * and give it to the stack + */ + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Received Data pkt..."); + skb_reserve(skb, 2 + SKB_RESERVE_PHS_BYTES); + memcpy(skb->data+ETH_HLEN, (PUCHAR)urb->transfer_buffer + sizeof(struct bcm_leader), pLeader->PLength); + skb->dev = Adapter->dev; + + /* currently skb->len has extra ETH_HLEN bytes in the beginning */ + skb_put(skb, pLeader->PLength + ETH_HLEN); + Adapter->PackInfo[QueueIndex].uiTotalRxBytes += pLeader->PLength; + Adapter->PackInfo[QueueIndex].uiThisPeriodRxBytes += pLeader->PLength; + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "Received Data pkt of len :0x%X", pLeader->PLength); + + if (netif_running(Adapter->dev)) { + /* Moving ahead by ETH_HLEN to the data ptr as received from FW */ + skb_pull(skb, ETH_HLEN); + PHSReceive(Adapter, pLeader->Vcid, skb, &skb->len, + NULL, bHeaderSupressionEnabled); + + if (!Adapter->PackInfo[QueueIndex].bEthCSSupport) { + skb_push(skb, ETH_HLEN); + + memcpy(skb->data, skb->dev->dev_addr, 6); + memcpy(skb->data+6, skb->dev->dev_addr, 6); + (*(skb->data+11))++; + *(skb->data+12) = 0x08; + *(skb->data+13) = 0x00; + pLeader->PLength += ETH_HLEN; + } + + skb->protocol = eth_type_trans(skb, Adapter->dev); + process_done = netif_rx(skb); + } else { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DATA, DBG_LVL_ALL, "i/f not up hance freeing SKB..."); + dev_kfree_skb(skb); + } + + ++Adapter->dev->stats.rx_packets; + Adapter->dev->stats.rx_bytes += pLeader->PLength; + + for (uiIndex = 0; uiIndex < MIBS_MAX_HIST_ENTRIES; uiIndex++) { + if ((pLeader->PLength <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1)) && + (pLeader->PLength > MIBS_PKTSIZEHIST_RANGE*(uiIndex))) + Adapter->aRxPktSizeHist[uiIndex]++; + } + } + Adapter->PrevNumRecvDescs++; + pRcb->bUsed = false; + atomic_dec(&psIntfAdapter->uNumRcbUsed); +} + +static int ReceiveRcb(struct bcm_interface_adapter *psIntfAdapter, struct bcm_usb_rcb *pRcb) +{ + struct urb *urb = pRcb->urb; + int retval = 0; + + usb_fill_bulk_urb(urb, psIntfAdapter->udev, usb_rcvbulkpipe(psIntfAdapter->udev, psIntfAdapter->sBulkIn.bulk_in_endpointAddr), + urb->transfer_buffer, BCM_USB_MAX_READ_LENGTH, read_bulk_callback, pRcb); + if (false == psIntfAdapter->psAdapter->device_removed && + false == psIntfAdapter->psAdapter->bEndPointHalted && + false == psIntfAdapter->bSuspended && + false == psIntfAdapter->bPreparingForBusSuspend) { + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "failed submitting read urb, error %d", retval); + /* if this return value is because of pipe halt. need to clear this. */ + if (retval == -EPIPE) { + psIntfAdapter->psAdapter->bEndPointHalted = TRUE; + wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue); + } + + } + } + return retval; +} + +/* +Function: InterfaceRx + +Description: This is the hardware specific Function for Receiving + data packet/control packets from the device. + +Input parameters: IN struct bcm_mini_adapter *Adapter - Miniport Adapter Context + + + +Return: TRUE - If Rx was successful. + Other - If an error occurred. +*/ + +bool InterfaceRx(struct bcm_interface_adapter *psIntfAdapter) +{ + USHORT RxDescCount = NUM_RX_DESC - atomic_read(&psIntfAdapter->uNumRcbUsed); + struct bcm_usb_rcb *pRcb = NULL; + + while (RxDescCount) { + pRcb = GetBulkInRcb(psIntfAdapter); + if (pRcb == NULL) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Unable to get Rcb pointer"); + return false; + } + ReceiveRcb(psIntfAdapter, pRcb); + RxDescCount--; + } + return TRUE; +} + diff --git a/drivers/staging/bcm/InterfaceRx.h b/drivers/staging/bcm/InterfaceRx.h new file mode 100644 index 00000000000..b4e858bcda3 --- /dev/null +++ b/drivers/staging/bcm/InterfaceRx.h @@ -0,0 +1,7 @@ +#ifndef _INTERFACE_RX_H +#define _INTERFACE_RX_H + +bool InterfaceRx(struct bcm_interface_adapter *Adapter); + +#endif + diff --git a/drivers/staging/bcm/InterfaceTx.c b/drivers/staging/bcm/InterfaceTx.c new file mode 100644 index 00000000000..ea7707b8e60 --- /dev/null +++ b/drivers/staging/bcm/InterfaceTx.c @@ -0,0 +1,174 @@ +#include "headers.h" + +/*this is transmit call-back(BULK OUT)*/ +static void write_bulk_callback(struct urb *urb/*, struct pt_regs *regs*/) +{ + struct bcm_usb_tcb *pTcb = (struct bcm_usb_tcb *)urb->context; + struct bcm_interface_adapter *psIntfAdapter = pTcb->psIntfAdapter; + struct bcm_link_request *pControlMsg = (struct bcm_link_request *)urb->transfer_buffer; + struct bcm_mini_adapter *psAdapter = psIntfAdapter->psAdapter; + bool bpowerDownMsg = false; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + if (unlikely(netif_msg_tx_done(Adapter))) + pr_info(PFX "%s: transmit status %d\n", Adapter->dev->name, urb->status); + + if (urb->status != STATUS_SUCCESS) { + if (urb->status == -EPIPE) { + psIntfAdapter->psAdapter->bEndPointHalted = TRUE; + wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Tx URB has got cancelled. status :%d", urb->status); + } + } + + pTcb->bUsed = false; + atomic_dec(&psIntfAdapter->uNumTcbUsed); + + + + if (TRUE == psAdapter->bPreparingForLowPowerMode) { + + if (((pControlMsg->szData[0] == GO_TO_IDLE_MODE_PAYLOAD) && + (pControlMsg->szData[1] == TARGET_CAN_GO_TO_IDLE_MODE))) { + bpowerDownMsg = TRUE; + /* This covers the bus err while Idle Request msg sent down. */ + if (urb->status != STATUS_SUCCESS) { + psAdapter->bPreparingForLowPowerMode = false; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Idle Mode Request msg failed to reach to Modem"); + /* Signalling the cntrl pkt path in Ioctl */ + wake_up(&psAdapter->lowpower_mode_wait_queue); + StartInterruptUrb(psIntfAdapter); + goto err_exit; + } + + if (psAdapter->bDoSuspend == false) { + psAdapter->IdleMode = TRUE; + /* since going in Idle mode completed hence making this var false */ + psAdapter->bPreparingForLowPowerMode = false; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Host Entered in Idle Mode State..."); + /* Signalling the cntrl pkt path in Ioctl*/ + wake_up(&psAdapter->lowpower_mode_wait_queue); + } + + } else if ((pControlMsg->Leader.Status == LINK_UP_CONTROL_REQ) && + (pControlMsg->szData[0] == LINK_UP_ACK) && + (pControlMsg->szData[1] == LINK_SHUTDOWN_REQ_FROM_FIRMWARE) && + (pControlMsg->szData[2] == SHUTDOWN_ACK_FROM_DRIVER)) { + /* This covers the bus err while shutdown Request msg sent down. */ + if (urb->status != STATUS_SUCCESS) { + psAdapter->bPreparingForLowPowerMode = false; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Shutdown Request Msg failed to reach to Modem"); + /* Signalling the cntrl pkt path in Ioctl */ + wake_up(&psAdapter->lowpower_mode_wait_queue); + StartInterruptUrb(psIntfAdapter); + goto err_exit; + } + + bpowerDownMsg = TRUE; + if (psAdapter->bDoSuspend == false) { + psAdapter->bShutStatus = TRUE; + /* since going in shutdown mode completed hence making this var false */ + psAdapter->bPreparingForLowPowerMode = false; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Host Entered in shutdown Mode State..."); + /* Signalling the cntrl pkt path in Ioctl */ + wake_up(&psAdapter->lowpower_mode_wait_queue); + } + } + + if (psAdapter->bDoSuspend && bpowerDownMsg) { + /* issuing bus suspend request */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Issuing the Bus suspend request to USB stack"); + psIntfAdapter->bPreparingForBusSuspend = TRUE; + schedule_work(&psIntfAdapter->usbSuspendWork); + + } + + } + +err_exit: + usb_free_coherent(urb->dev, urb->transfer_buffer_length, + urb->transfer_buffer, urb->transfer_dma); +} + + +static struct bcm_usb_tcb *GetBulkOutTcb(struct bcm_interface_adapter *psIntfAdapter) +{ + struct bcm_usb_tcb *pTcb = NULL; + UINT index = 0; + + if ((atomic_read(&psIntfAdapter->uNumTcbUsed) < MAXIMUM_USB_TCB) && + (psIntfAdapter->psAdapter->StopAllXaction == false)) { + index = atomic_read(&psIntfAdapter->uCurrTcb); + pTcb = &psIntfAdapter->asUsbTcb[index]; + pTcb->bUsed = TRUE; + pTcb->psIntfAdapter = psIntfAdapter; + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Got Tx desc %d used %d", + index, atomic_read(&psIntfAdapter->uNumTcbUsed)); + index = (index + 1) % MAXIMUM_USB_TCB; + atomic_set(&psIntfAdapter->uCurrTcb, index); + atomic_inc(&psIntfAdapter->uNumTcbUsed); + } + return pTcb; +} + +static int TransmitTcb(struct bcm_interface_adapter *psIntfAdapter, struct bcm_usb_tcb *pTcb, PVOID data, int len) +{ + + struct urb *urb = pTcb->urb; + int retval = 0; + + urb->transfer_buffer = usb_alloc_coherent(psIntfAdapter->udev, len, + GFP_ATOMIC, &urb->transfer_dma); + if (!urb->transfer_buffer) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "Error allocating memory\n"); + return -ENOMEM; + } + memcpy(urb->transfer_buffer, data, len); + urb->transfer_buffer_length = len; + + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "Sending Bulk out packet\n"); + /* For T3B,INT OUT end point will be used as bulk out end point */ + if ((psIntfAdapter->psAdapter->chip_id == T3B) && (psIntfAdapter->bHighSpeedDevice == TRUE)) { + usb_fill_int_urb(urb, psIntfAdapter->udev, + psIntfAdapter->sBulkOut.bulk_out_pipe, + urb->transfer_buffer, len, write_bulk_callback, pTcb, + psIntfAdapter->sBulkOut.int_out_interval); + } else { + usb_fill_bulk_urb(urb, psIntfAdapter->udev, + psIntfAdapter->sBulkOut.bulk_out_pipe, + urb->transfer_buffer, len, write_bulk_callback, pTcb); + } + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* For DMA transfer */ + + if (false == psIntfAdapter->psAdapter->device_removed && + false == psIntfAdapter->psAdapter->bEndPointHalted && + false == psIntfAdapter->bSuspended && + false == psIntfAdapter->bPreparingForBusSuspend) { + retval = usb_submit_urb(urb, GFP_ATOMIC); + if (retval) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "failed submitting write urb, error %d", retval); + if (retval == -EPIPE) { + psIntfAdapter->psAdapter->bEndPointHalted = TRUE; + wake_up(&psIntfAdapter->psAdapter->tx_packet_wait_queue); + } + } + } + return retval; +} + +int InterfaceTransmitPacket(PVOID arg, PVOID data, UINT len) +{ + struct bcm_usb_tcb *pTcb = NULL; + + struct bcm_interface_adapter *psIntfAdapter = arg; + pTcb = GetBulkOutTcb(psIntfAdapter); + if (pTcb == NULL) { + BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "No URB to transmit packet, dropping packet"); + return -EFAULT; + } + return TransmitTcb(psIntfAdapter, pTcb, data, len); +} + + diff --git a/drivers/staging/bcm/InterfaceTx.h b/drivers/staging/bcm/InterfaceTx.h new file mode 100644 index 00000000000..273147577c1 --- /dev/null +++ b/drivers/staging/bcm/InterfaceTx.h @@ -0,0 +1,7 @@ +#ifndef _INTERFACE_TX_H +#define _INTERFACE_TX_H + +INT InterfaceTransmitPacket(PVOID arg, PVOID data, UINT len); + +#endif + diff --git a/drivers/staging/bcm/Ioctl.h b/drivers/staging/bcm/Ioctl.h new file mode 100644 index 00000000000..797f862b90c --- /dev/null +++ b/drivers/staging/bcm/Ioctl.h @@ -0,0 +1,226 @@ +#ifndef _IOCTL_H_ +#define _IOCTL_H_ + +struct bcm_rdm_buffer { + unsigned long Register; + unsigned long Length; +} __packed; + +struct bcm_wrm_buffer { + unsigned long Register; + unsigned long Length; + unsigned char Data[4]; +} __packed; + +struct bcm_ioctl_buffer { + void __user *InputBuffer; + unsigned long InputLength; + void __user *OutputBuffer; + unsigned long OutputLength; +} __packed; + +struct bcm_gpio_info { + unsigned int uiGpioNumber; /* valid numbers 0-15 */ + unsigned int uiGpioValue; /* 1 set ; 0 not set */ +} __packed; + +struct bcm_user_thread_req { + /* 0->Inactivate LED thread. */ + /* 1->Activate the LED thread */ + unsigned int ThreadState; +} __packed; + +#define LED_THREAD_ACTIVATION_REQ 1 +#define BCM_IOCTL 'k' +#define IOCTL_SEND_CONTROL_MESSAGE _IOW(BCM_IOCTL, 0x801, int) +#define IOCTL_BCM_REGISTER_WRITE _IOW(BCM_IOCTL, 0x802, int) +#define IOCTL_BCM_REGISTER_READ _IOR(BCM_IOCTL, 0x803, int) +#define IOCTL_BCM_COMMON_MEMORY_WRITE _IOW(BCM_IOCTL, 0x804, int) +#define IOCTL_BCM_COMMON_MEMORY_READ _IOR(BCM_IOCTL, 0x805, int) +#define IOCTL_GET_CONTROL_MESSAGE _IOR(BCM_IOCTL, 0x806, int) +#define IOCTL_BCM_FIRMWARE_DOWNLOAD _IOW(BCM_IOCTL, 0x807, int) +#define IOCTL_BCM_SET_SEND_VCID _IOW(BCM_IOCTL, 0x808, int) +#define IOCTL_BCM_SWITCH_TRANSFER_MODE _IOW(BCM_IOCTL, 0x809, int) +#define IOCTL_LINK_REQ _IOW(BCM_IOCTL, 0x80A, int) +#define IOCTL_RSSI_LEVEL_REQ _IOW(BCM_IOCTL, 0x80B, int) +#define IOCTL_IDLE_REQ _IOW(BCM_IOCTL, 0x80C, int) +#define IOCTL_SS_INFO_REQ _IOW(BCM_IOCTL, 0x80D, int) +#define IOCTL_GET_STATISTICS_POINTER _IOW(BCM_IOCTL, 0x80E, int) +#define IOCTL_CM_REQUEST _IOW(BCM_IOCTL, 0x80F, int) +#define IOCTL_INIT_PARAM_REQ _IOW(BCM_IOCTL, 0x810, int) +#define IOCTL_MAC_ADDR_REQ _IOW(BCM_IOCTL, 0x811, int) +#define IOCTL_MAC_ADDR_RESP _IOWR(BCM_IOCTL, 0x812, int) +#define IOCTL_CLASSIFICATION_RULE _IOW(BCM_IOCTL, 0x813, char) +#define IOCTL_CLOSE_NOTIFICATION _IO(BCM_IOCTL, 0x814) +#define IOCTL_LINK_UP _IO(BCM_IOCTL, 0x815) +#define IOCTL_LINK_DOWN _IO(BCM_IOCTL, 0x816, struct bcm_ioctl_buffer) +#define IOCTL_CHIP_RESET _IO(BCM_IOCTL, 0x816) +#define IOCTL_CINR_LEVEL_REQ _IOW(BCM_IOCTL, 0x817, char) +#define IOCTL_WTM_CONTROL_REQ _IOW(BCM_IOCTL, 0x817, char) +#define IOCTL_BE_BUCKET_SIZE _IOW(BCM_IOCTL, 0x818, unsigned long) +#define IOCTL_RTPS_BUCKET_SIZE _IOW(BCM_IOCTL, 0x819, unsigned long) +#define IOCTL_QOS_THRESHOLD _IOW(BCM_IOCTL, 0x820, unsigned long) +#define IOCTL_DUMP_PACKET_INFO _IO(BCM_IOCTL, 0x821) +#define IOCTL_GET_PACK_INFO _IOR(BCM_IOCTL, 0x823, int) +#define IOCTL_BCM_GET_DRIVER_VERSION _IOR(BCM_IOCTL, 0x829, int) +#define IOCTL_BCM_GET_CURRENT_STATUS _IOW(BCM_IOCTL, 0x828, int) +#define IOCTL_BCM_GPIO_SET_REQUEST _IOW(BCM_IOCTL, 0x82A, int) +#define IOCTL_BCM_GPIO_STATUS_REQUEST _IOW(BCM_IOCTL, 0x82b, int) +#define IOCTL_BCM_GET_DSX_INDICATION _IOR(BCM_IOCTL, 0x854, int) +#define IOCTL_BCM_BUFFER_DOWNLOAD_START _IOW(BCM_IOCTL, 0x855, int) +#define IOCTL_BCM_BUFFER_DOWNLOAD _IOW(BCM_IOCTL, 0x856, int) +#define IOCTL_BCM_BUFFER_DOWNLOAD_STOP _IOW(BCM_IOCTL, 0x857, int) +#define IOCTL_BCM_REGISTER_WRITE_PRIVATE _IOW(BCM_IOCTL, 0x826, char) +#define IOCTL_BCM_REGISTER_READ_PRIVATE _IOW(BCM_IOCTL, 0x827, char) +#define IOCTL_BCM_SET_DEBUG _IOW(BCM_IOCTL, 0x824, struct bcm_ioctl_buffer) +#define IOCTL_BCM_EEPROM_REGISTER_WRITE _IOW(BCM_IOCTL, 0x858, int) +#define IOCTL_BCM_EEPROM_REGISTER_READ _IOR(BCM_IOCTL, 0x859, int) +#define IOCTL_BCM_WAKE_UP_DEVICE_FROM_IDLE _IOR(BCM_IOCTL, 0x860, int) +#define IOCTL_BCM_SET_MAC_TRACING _IOW(BCM_IOCTL, 0x82c, int) +#define IOCTL_BCM_GET_HOST_MIBS _IOW(BCM_IOCTL, 0x853, int) +#define IOCTL_BCM_NVM_READ _IOR(BCM_IOCTL, 0x861, int) +#define IOCTL_BCM_NVM_WRITE _IOW(BCM_IOCTL, 0x862, int) +#define IOCTL_BCM_GET_NVM_SIZE _IOR(BCM_IOCTL, 0x863, int) +#define IOCTL_BCM_CAL_INIT _IOR(BCM_IOCTL, 0x864, int) +#define IOCTL_BCM_BULK_WRM _IOW(BCM_IOCTL, 0x90B, int) +#define IOCTL_BCM_FLASH2X_SECTION_READ _IOR(BCM_IOCTL, 0x865, int) +#define IOCTL_BCM_FLASH2X_SECTION_WRITE _IOW(BCM_IOCTL, 0x866, int) +#define IOCTL_BCM_GET_FLASH2X_SECTION_BITMAP _IOR(BCM_IOCTL, 0x867, int) +#define IOCTL_BCM_SET_ACTIVE_SECTION _IOW(BCM_IOCTL, 0x868, int) +#define IOCTL_BCM_IDENTIFY_ACTIVE_SECTION _IO(BCM_IOCTL, 0x869) +#define IOCTL_BCM_COPY_SECTION _IOW(BCM_IOCTL, 0x870, int) +#define IOCTL_BCM_GET_FLASH_CS_INFO _IOR(BCM_IOCTL, 0x871, int) +#define IOCTL_BCM_SELECT_DSD _IOW(BCM_IOCTL, 0x872, int) +#define IOCTL_BCM_NVM_RAW_READ _IOR(BCM_IOCTL, 0x875, int) +#define IOCTL_BCM_CNTRLMSG_MASK _IOW(BCM_IOCTL, 0x874, int) +#define IOCTL_BCM_GET_DEVICE_DRIVER_INFO _IOR(BCM_IOCTL, 0x877, int) +#define IOCTL_BCM_TIME_SINCE_NET_ENTRY _IOR(BCM_IOCTL, 0x876, int) +#define BCM_LED_THREAD_STATE_CHANGE_REQ _IOW(BCM_IOCTL, 0x878, int) +#define IOCTL_BCM_GPIO_MULTI_REQUEST _IOW(BCM_IOCTL, 0x82D, struct bcm_ioctl_buffer) +#define IOCTL_BCM_GPIO_MODE_REQUEST _IOW(BCM_IOCTL, 0x82E, struct bcm_ioctl_buffer) + +enum bcm_interface_type { + BCM_MII, + BCM_CARDBUS, + BCM_USB, + BCM_SDIO, + BCM_PCMCIA +}; + +struct bcm_driver_info { + enum bcm_nvm_type u32NVMType; + unsigned int MaxRDMBufferSize; + enum bcm_interface_type u32InterfaceType; + unsigned int u32DSDStartOffset; + unsigned int u32RxAlignmentCorrection; + unsigned int u32Reserved[10]; +}; + +struct bcm_nvm_readwrite { + void __user *pBuffer; + uint32_t uiOffset; + uint32_t uiNumBytes; + bool bVerify; +}; + +struct bcm_bulk_wrm_buffer { + unsigned long Register; + unsigned long SwapEndian; + unsigned long Values[1]; +}; + +enum bcm_flash2x_section_val { + NO_SECTION_VAL = 0, /* no section is chosen when absolute offset is given for RD/WR */ + ISO_IMAGE1, + ISO_IMAGE2, + DSD0, + DSD1, + DSD2, + VSA0, + VSA1, + VSA2, + SCSI, + CONTROL_SECTION, + ISO_IMAGE1_PART2, + ISO_IMAGE1_PART3, + ISO_IMAGE2_PART2, + ISO_IMAGE2_PART3, + TOTAL_SECTIONS +}; + +/* + * Structure used for READ/WRITE Flash Map2.x + */ +struct bcm_flash2x_readwrite { + enum bcm_flash2x_section_val Section; /* which section has to be read/written */ + u32 offset; /* Offset within Section. */ + u32 numOfBytes; /* NOB from the offset */ + u32 bVerify; + void __user *pDataBuff; /* Buffer for reading/writing */ +}; + +/* + * This structure is used for coping one section to other. + * there are two ways to copy one section to other. + * it NOB =0, complete section will be copied on to other. + * if NOB !=0, only NOB will be copied from the given offset. + */ + +struct bcm_flash2x_copy_section { + enum bcm_flash2x_section_val SrcSection; + enum bcm_flash2x_section_val DstSection; + u32 offset; + u32 numOfBytes; +}; + +/* + * This section provide the complete bitmap of the Flash. + * using this map lib/APP will issue read/write command. + * Fields are defined as : + * Bit [0] = section is present //1:present, 0: Not present + * Bit [1] = section is valid //1: valid, 0: not valid + * Bit [2] = Section is R/W //0: RW, 1: RO + * Bit [3] = Section is Active or not 1 means Active, 0->inactive + * Bit [7...3] = Reserved + */ + +struct bcm_flash2x_bitmap { + unsigned char ISO_IMAGE1; + unsigned char ISO_IMAGE2; + unsigned char DSD0; + unsigned char DSD1; + unsigned char DSD2; + unsigned char VSA0; + unsigned char VSA1; + unsigned char VSA2; + unsigned char SCSI; + unsigned char CONTROL_SECTION; + /* Reserved for future use */ + unsigned char Reserved0; + unsigned char Reserved1; + unsigned char Reserved2; +}; + +struct bcm_time_elapsed { + u64 ul64TimeElapsedSinceNetEntry; + u32 uiReserved[4]; +}; + +enum { + WIMAX_IDX = 0, /* To access WiMAX chip GPIO's for GPIO_MULTI_INFO or GPIO_MULTI_MODE */ + HOST_IDX, /* To access Host chip GPIO's for GPIO_MULTI_INFO or GPIO_MULTI_MODE */ + MAX_IDX +}; + +struct bcm_gpio_multi_info { + unsigned int uiGPIOCommand; /* 1 for set and 0 for get */ + unsigned int uiGPIOMask; /* set the correspondig bit to 1 to access GPIO */ + unsigned int uiGPIOValue; /* 0 or 1; value to be set when command is 1. */ +} __packed; + +struct bcm_gpio_multi_mode { + unsigned int uiGPIOMode; /* 1 for OUT mode, 0 for IN mode */ + unsigned int uiGPIOMask; /* GPIO mask to set mode */ +} __packed; + +#endif diff --git a/drivers/staging/bcm/Kconfig b/drivers/staging/bcm/Kconfig new file mode 100644 index 00000000000..8acf4b24a7c --- /dev/null +++ b/drivers/staging/bcm/Kconfig @@ -0,0 +1,6 @@ +config BCM_WIMAX + tristate "Beceem BCS200/BCS220-3 and BCSM250 wimax support" + depends on USB && NET + help + This is an experimental driver for the Beceem WIMAX chipset used + by Sprint 4G. diff --git a/drivers/staging/bcm/LeakyBucket.c b/drivers/staging/bcm/LeakyBucket.c new file mode 100644 index 00000000000..f95b06713a2 --- /dev/null +++ b/drivers/staging/bcm/LeakyBucket.c @@ -0,0 +1,317 @@ +/********************************************************************** +* LEAKYBUCKET.C +* This file contains the routines related to Leaky Bucket Algorithm. +***********************************************************************/ +#include "headers.h" + +/********************************************************************* +* Function - UpdateTokenCount() +* +* Description - This function calculates the token count for each +* channel and updates the same in Adapter strucuture. +* +* Parameters - Adapter: Pointer to the Adapter structure. +* +* Returns - None +**********************************************************************/ + +static VOID UpdateTokenCount(register struct bcm_mini_adapter *Adapter) +{ + ULONG liCurrentTime; + INT i = 0; + struct timeval tv; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, + "=====>\n"); + if (NULL == Adapter) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, + DBG_LVL_ALL, "Adapter found NULL!\n"); + return; + } + + do_gettimeofday(&tv); + for (i = 0; i < NO_OF_QUEUES; i++) { + if (TRUE == Adapter->PackInfo[i].bValid && + (1 == Adapter->PackInfo[i].ucDirection)) { + liCurrentTime = ((tv.tv_sec- + Adapter->PackInfo[i].stLastUpdateTokenAt.tv_sec)*1000 + + (tv.tv_usec-Adapter->PackInfo[i].stLastUpdateTokenAt.tv_usec)/ + 1000); + if (0 != liCurrentTime) { + Adapter->PackInfo[i].uiCurrentTokenCount += (ULONG) + ((Adapter->PackInfo[i].uiMaxAllowedRate) * + ((ULONG)((liCurrentTime)))/1000); + memcpy(&Adapter->PackInfo[i].stLastUpdateTokenAt, + &tv, sizeof(struct timeval)); + Adapter->PackInfo[i].liLastUpdateTokenAt = liCurrentTime; + if (Adapter->PackInfo[i].uiCurrentTokenCount >= + Adapter->PackInfo[i].uiMaxBucketSize) { + Adapter->PackInfo[i].uiCurrentTokenCount = + Adapter->PackInfo[i].uiMaxBucketSize; + } + } + } + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "<=====\n"); + return; + +} + + +/********************************************************************* +* Function - IsPacketAllowedForFlow() +* +* Description - This function checks whether the given packet from the +* specified queue can be allowed for transmission by +* checking the token count. +* +* Parameters - Adapter : Pointer to the Adpater structure. +* - iQIndex : The queue Identifier. +* - ulPacketLength: Number of bytes to be transmitted. +* +* Returns - The number of bytes allowed for transmission. +* +***********************************************************************/ +static ULONG GetSFTokenCount(struct bcm_mini_adapter *Adapter, struct bcm_packet_info *psSF) +{ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow ===>"); + /* Validate the parameters */ + if (NULL == Adapter || (psSF < Adapter->PackInfo && + (uintptr_t)psSF > (uintptr_t) &Adapter->PackInfo[HiPriority])) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Got wrong Parameters:Adapter: %p, QIndex: %zd\n", Adapter, (psSF-Adapter->PackInfo)); + return 0; + } + + if (false != psSF->bValid && psSF->ucDirection) { + if (0 != psSF->uiCurrentTokenCount) { + return psSF->uiCurrentTokenCount; + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "Not enough tokens in queue %zd Available %u\n", + psSF-Adapter->PackInfo, psSF->uiCurrentTokenCount); + psSF->uiPendedLast = 1; + } + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IPAFF: Queue %zd not valid\n", psSF-Adapter->PackInfo); + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TOKEN_COUNTS, DBG_LVL_ALL, "IsPacketAllowedForFlow <==="); + return 0; +} + +/** +@ingroup tx_functions +This function despatches packet from the specified queue. +@return Zero(success) or Negative value(failure) +*/ +static INT SendPacketFromQueue(struct bcm_mini_adapter *Adapter,/**<Logical Adapter*/ + struct bcm_packet_info *psSF, /**<Queue identifier*/ + struct sk_buff *Packet) /**<Pointer to the packet to be sent*/ +{ + INT Status = STATUS_FAILURE; + UINT uiIndex = 0, PktLen = 0; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "=====>"); + if (!Adapter || !Packet || !psSF) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "Got NULL Adapter or Packet"); + return -EINVAL; + } + + if (psSF->liDrainCalculated == 0) + psSF->liDrainCalculated = jiffies; + /* send the packet to the fifo.. */ + PktLen = Packet->len; + Status = SetupNextSend(Adapter, Packet, psSF->usVCID_Value); + if (Status == 0) { + for (uiIndex = 0; uiIndex < MIBS_MAX_HIST_ENTRIES; uiIndex++) { + if ((PktLen <= MIBS_PKTSIZEHIST_RANGE*(uiIndex+1)) && (PktLen > MIBS_PKTSIZEHIST_RANGE*(uiIndex))) + Adapter->aTxPktSizeHist[uiIndex]++; + } + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, SEND_QUEUE, DBG_LVL_ALL, "<====="); + return Status; +} + +/************************************************************************ +* Function - CheckAndSendPacketFromIndex() +* +* Description - This function dequeues the data/control packet from the +* specified queue for transmission. +* +* Parameters - Adapter : Pointer to the driver control structure. +* - iQIndex : The queue Identifier. +* +* Returns - None. +* +****************************************************************************/ +static VOID CheckAndSendPacketFromIndex(struct bcm_mini_adapter *Adapter, struct bcm_packet_info *psSF) +{ + struct sk_buff *QueuePacket = NULL; + char *pControlPacket = NULL; + INT Status = 0; + int iPacketLen = 0; + + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "%zd ====>", (psSF-Adapter->PackInfo)); + if ((psSF != &Adapter->PackInfo[HiPriority]) && Adapter->LinkUpStatus && atomic_read(&psSF->uiPerSFTxResourceCount)) { /* Get data packet */ + if (!psSF->ucDirection) + return; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "UpdateTokenCount "); + if (Adapter->IdleMode || Adapter->bPreparingForLowPowerMode) + return; /* in idle mode */ + + /* Check for Free Descriptors */ + if (atomic_read(&Adapter->CurrNumFreeTxDesc) <= MINIMUM_PENDING_DESCRIPTORS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " No Free Tx Descriptor(%d) is available for Data pkt..", atomic_read(&Adapter->CurrNumFreeTxDesc)); + return; + } + + spin_lock_bh(&psSF->SFQueueLock); + QueuePacket = psSF->FirstTxQueue; + + if (QueuePacket) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Dequeuing Data Packet"); + + if (psSF->bEthCSSupport) + iPacketLen = QueuePacket->len; + else + iPacketLen = QueuePacket->len-ETH_HLEN; + + iPacketLen <<= 3; + if (iPacketLen <= GetSFTokenCount(Adapter, psSF)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Allowed bytes %d", + (iPacketLen >> 3)); + + DEQUEUEPACKET(psSF->FirstTxQueue, psSF->LastTxQueue); + psSF->uiCurrentBytesOnHost -= (QueuePacket->len); + psSF->uiCurrentPacketsOnHost--; + atomic_dec(&Adapter->TotalPacketCount); + spin_unlock_bh(&psSF->SFQueueLock); + + Status = SendPacketFromQueue(Adapter, psSF, QueuePacket); + psSF->uiPendedLast = false; + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "For Queue: %zd\n", psSF-Adapter->PackInfo); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nAvailable Tokens = %d required = %d\n", + psSF->uiCurrentTokenCount, iPacketLen); + /* + this part indicates that because of non-availability of the tokens + pkt has not been send out hence setting the pending flag indicating the host to send it out + first next iteration. + */ + psSF->uiPendedLast = TRUE; + spin_unlock_bh(&psSF->SFQueueLock); + } + } else { + spin_unlock_bh(&psSF->SFQueueLock); + } + } else { + + if ((atomic_read(&Adapter->CurrNumFreeTxDesc) > 0) && + (atomic_read(&Adapter->index_rd_txcntrlpkt) != + atomic_read(&Adapter->index_wr_txcntrlpkt))) { + pControlPacket = Adapter->txctlpacket + [(atomic_read(&Adapter->index_rd_txcntrlpkt)%MAX_CNTRL_PKTS)]; + if (pControlPacket) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Sending Control packet"); + Status = SendControlPacket(Adapter, pControlPacket); + if (STATUS_SUCCESS == Status) { + spin_lock_bh(&psSF->SFQueueLock); + psSF->NumOfPacketsSent++; + psSF->uiSentBytes += ((struct bcm_leader *)pControlPacket)->PLength; + psSF->uiSentPackets++; + atomic_dec(&Adapter->TotalPacketCount); + psSF->uiCurrentBytesOnHost -= ((struct bcm_leader *)pControlPacket)->PLength; + psSF->uiCurrentPacketsOnHost--; + atomic_inc(&Adapter->index_rd_txcntrlpkt); + spin_unlock_bh(&psSF->SFQueueLock); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "SendControlPacket Failed\n"); + } + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, " Control Pkt is not available, Indexing is wrong...."); + } + } + } +} + + +/******************************************************************* +* Function - transmit_packets() +* +* Description - This function transmits the packets from different +* queues, if free descriptors are available on target. +* +* Parameters - Adapter: Pointer to the Adapter structure. +* +* Returns - None. +********************************************************************/ +VOID transmit_packets(struct bcm_mini_adapter *Adapter) +{ + UINT uiPrevTotalCount = 0; + int iIndex = 0; + + bool exit_flag = TRUE; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "=====>"); + + if (NULL == Adapter) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Got NULL Adapter"); + return; + } + if (Adapter->device_removed == TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Device removed"); + return; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nUpdateTokenCount ====>\n"); + + UpdateTokenCount(Adapter); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "\nPruneQueueAllSF ====>\n"); + + PruneQueueAllSF(Adapter); + + uiPrevTotalCount = atomic_read(&Adapter->TotalPacketCount); + + for (iIndex = HiPriority; iIndex >= 0; iIndex--) { + if (!uiPrevTotalCount || (TRUE == Adapter->device_removed)) + break; + + if (Adapter->PackInfo[iIndex].bValid && + Adapter->PackInfo[iIndex].uiPendedLast && + Adapter->PackInfo[iIndex].uiCurrentBytesOnHost) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling CheckAndSendPacketFromIndex.."); + CheckAndSendPacketFromIndex(Adapter, &Adapter->PackInfo[iIndex]); + uiPrevTotalCount--; + } + } + + while (uiPrevTotalCount > 0 && !Adapter->device_removed) { + exit_flag = TRUE; + /* second iteration to parse non-pending queues */ + for (iIndex = HiPriority; iIndex >= 0; iIndex--) { + if (!uiPrevTotalCount || (TRUE == Adapter->device_removed)) + break; + + if (Adapter->PackInfo[iIndex].bValid && + Adapter->PackInfo[iIndex].uiCurrentBytesOnHost && + !Adapter->PackInfo[iIndex].uiPendedLast) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling CheckAndSendPacketFromIndex.."); + CheckAndSendPacketFromIndex(Adapter, &Adapter->PackInfo[iIndex]); + uiPrevTotalCount--; + exit_flag = false; + } + } + + if (Adapter->IdleMode || Adapter->bPreparingForLowPowerMode) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "In Idle Mode\n"); + break; + } + if (exit_flag == TRUE) + break; + } /* end of inner while loop */ + + update_per_cid_rx(Adapter); + Adapter->txtransmit_running = 0; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "<======"); +} diff --git a/drivers/staging/bcm/Macros.h b/drivers/staging/bcm/Macros.h new file mode 100644 index 00000000000..dc01e3016d4 --- /dev/null +++ b/drivers/staging/bcm/Macros.h @@ -0,0 +1,352 @@ +/************************************* +* Macros.h +**************************************/ +#ifndef __MACROS_H__ +#define __MACROS_H__ + +#define TX_TIMER_PERIOD 10 /*10 msec*/ +#define MAX_CLASSIFIERS 100 +#define MAX_TARGET_DSX_BUFFERS 24 + +#define MAX_CNTRL_PKTS 100 +#define MAX_DATA_PKTS 200 +#define MAX_ETH_SIZE 1536 +#define MAX_CNTL_PKT_SIZE 2048 + +#define MTU_SIZE 1400 +#define TX_QLEN 5 + +#define MAC_ADDR_REGISTER 0xbf60d000 + + +/* Quality of Service */ +#define NO_OF_QUEUES 17 +#define HiPriority (NO_OF_QUEUES-1) +#define LowPriority 0 +#define BE 2 +#define rtPS 4 +#define ERTPS 5 +#define UGS 6 + +#define BE_BUCKET_SIZE (1024*1024*100) /* 32kb */ +#define rtPS_BUCKET_SIZE (1024*1024*100) /* 8kb */ +#define MAX_ALLOWED_RATE (1024*1024*100) +#define TX_PACKET_THRESHOLD 10 +#define XSECONDS (1*HZ) +#define DSC_ACTIVATE_REQUEST 248 +#define QUEUE_DEPTH_OFFSET 0x1fc01000 +#define MAX_DEVICE_DESC_SIZE 2040 +#define MAX_CTRL_QUEUE_LEN 100 +#define MAX_APP_QUEUE_LEN 200 +#define MAX_LATENCY_ALLOWED 0xFFFFFFFF +#define DEFAULT_UG_INTERVAL 250 +#define DEFAULT_UGI_FACTOR 4 + +#define DEFAULT_PERSFCOUNT 60 +#define MAX_CONNECTIONS 10 +#define MAX_CLASS_NAME_LENGTH 32 + +#define ETH_LENGTH_OF_ADDRESS 6 +#define MAX_MULTICAST_ADDRESSES 32 +#define IP_LENGTH_OF_ADDRESS 4 + +#define IP_PACKET_ONLY_MODE 0 +#define ETH_PACKET_TUNNELING_MODE 1 + +/* Link Request */ +#define SET_MAC_ADDRESS_REQUEST 0 +#define SYNC_UP_REQUEST 1 +#define SYNCED_UP 2 +#define LINK_UP_REQUEST 3 +#define LINK_CONNECTED 4 +#define SYNC_UP_NOTIFICATION 2 +#define LINK_UP_NOTIFICATION 4 + + +#define LINK_NET_ENTRY 0x0002 +#define HMC_STATUS 0x0004 +#define LINK_UP_CONTROL_REQ 0x83 + +#define STATS_POINTER_REQ_STATUS 0x86 +#define NETWORK_ENTRY_REQ_PAYLOAD 198 +#define LINK_DOWN_REQ_PAYLOAD 226 +#define SYNC_UP_REQ_PAYLOAD 228 +#define STATISTICS_POINTER_REQ 237 +#define LINK_UP_REQ_PAYLOAD 245 +#define LINK_UP_ACK 246 + +#define STATS_MSG_SIZE 4 +#define INDEX_TO_DATA 4 + +#define GO_TO_IDLE_MODE_PAYLOAD 210 +#define COME_UP_FROM_IDLE_MODE_PAYLOAD 211 +#define IDLE_MODE_SF_UPDATE_MSG 187 + +#define SKB_RESERVE_ETHERNET_HEADER 16 +#define SKB_RESERVE_PHS_BYTES 32 + +#define IP_PACKET_ONLY_MODE 0 +#define ETH_PACKET_TUNNELING_MODE 1 + +#define ETH_CS_802_3 1 +#define ETH_CS_802_1Q_VLAN 3 +#define IPV4_CS 1 +#define IPV6_CS 2 +#define ETH_CS_MASK 0x3f + +/** \brief Validity bit maps for TLVs in packet classification rule */ + +#define PKT_CLASSIFICATION_USER_PRIORITY_VALID 0 +#define PKT_CLASSIFICATION_VLANID_VALID 1 + +#ifndef MIN +#define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b)) +#endif + + +/*Leader related terms */ +#define LEADER_STATUS 0x00 +#define LEADER_STATUS_TCP_ACK 0x1 +#define LEADER_SIZE sizeof(struct bcm_leader) +#define MAC_ADDR_REQ_SIZE sizeof(struct bcm_packettosend) +#define SS_INFO_REQ_SIZE sizeof(struct bcm_packettosend) +#define CM_REQUEST_SIZE (LEADER_SIZE + sizeof(stLocalSFChangeRequest)) +#define IDLE_REQ_SIZE sizeof(struct bcm_packettosend) + + +#define MAX_TRANSFER_CTRL_BYTE_USB (2*1024) + +#define GET_MAILBOX1_REG_REQUEST 0x87 +#define GET_MAILBOX1_REG_RESPONSE 0x67 +#define VCID_CONTROL_PACKET 0x00 + +#define TRANSMIT_NETWORK_DATA 0x00 +#define RECEIVED_NETWORK_DATA 0x20 + +#define CM_RESPONSES 0xA0 +#define STATUS_RSP 0xA1 +#define LINK_CONTROL_RESP 0xA2 +#define IDLE_MODE_STATUS 0xA3 +#define STATS_POINTER_RESP 0xA6 +#define MGMT_MSG_INFO_SW_STATUS 0xA7 +#define AUTH_SS_HOST_MSG 0xA8 + +#define CM_DSA_ACK_PAYLOAD 247 +#define CM_DSC_ACK_PAYLOAD 248 +#define CM_DSD_ACK_PAYLOAD 249 +#define CM_DSDEACTVATE 250 +#define TOTAL_MASKED_ADDRESS_IN_BYTES 32 + +#define MAC_REQ 0 +#define LINK_RESP 1 +#define RSSI_INDICATION 2 + +#define SS_INFO 4 +#define STATISTICS_INFO 5 +#define CM_INDICATION 6 +#define PARAM_RESP 7 +#define BUFFER_1K 1024 +#define BUFFER_2K (BUFFER_1K*2) +#define BUFFER_4K (BUFFER_2K*2) +#define BUFFER_8K (BUFFER_4K*2) +#define BUFFER_16K (BUFFER_8K*2) +#define DOWNLINK_DIR 0 +#define UPLINK_DIR 1 + +#define BCM_SIGNATURE "BECEEM" + + +#define GPIO_OUTPUT_REGISTER 0x0F00003C +#define BCM_GPIO_OUTPUT_SET_REG 0x0F000040 +#define BCM_GPIO_OUTPUT_CLR_REG 0x0F000044 +#define GPIO_MODE_REGISTER 0x0F000034 +#define GPIO_PIN_STATE_REGISTER 0x0F000038 + +struct bcm_link_state { + unsigned char ucLinkStatus; + unsigned char bIdleMode; + unsigned char bShutdownMode; +}; + +enum enLinkStatus { + WAIT_FOR_SYNC = 1, + PHY_SYNC_ACHIVED = 2, + LINKUP_IN_PROGRESS = 3, + LINKUP_DONE = 4, + DREG_RECEIVED = 5, + LINK_STATUS_RESET_RECEIVED = 6, + PERIODIC_WAKE_UP_NOTIFICATION_FRM_FW = 7, + LINK_SHUTDOWN_REQ_FROM_FIRMWARE = 8, + COMPLETE_WAKE_UP_NOTIFICATION_FRM_FW = 9 +}; + +enum bcm_phs_dsc_action { + eAddPHSRule = 0, + eSetPHSRule, + eDeletePHSRule, + eDeleteAllPHSRules +}; + +#define CM_CONTROL_NEWDSX_MULTICLASSIFIER_REQ 0x89 /* Host to Mac */ +#define CM_CONTROL_NEWDSX_MULTICLASSIFIER_RESP 0xA9 /* Mac to Host */ +#define MASK_DISABLE_HEADER_SUPPRESSION 0x10 /* 0b000010000 */ +#define MINIMUM_PENDING_DESCRIPTORS 5 + +#define SHUTDOWN_HOSTINITIATED_REQUESTPAYLOAD 0xCC +#define SHUTDOWN_ACK_FROM_DRIVER 0x1 +#define SHUTDOWN_NACK_FROM_DRIVER 0x2 + +#define LINK_SYNC_UP_SUBTYPE 0x0001 +#define LINK_SYNC_DOWN_SUBTYPE 0x0001 + + + +#define CONT_MODE 1 +#define SINGLE_DESCRIPTOR 1 + + +#define DESCRIPTOR_LENGTH 0x30 +#define FIRMWARE_DESCS_ADDRESS 0x1F100000 + + +#define CLOCK_RESET_CNTRL_REG_1 0x0F00000C +#define CLOCK_RESET_CNTRL_REG_2 0x0F000840 + + + +#define TX_DESCRIPTOR_HEAD_REGISTER 0x0F010034 +#define RX_DESCRIPTOR_HEAD_REGISTER 0x0F010094 + +#define STATISTICS_BEGIN_ADDR 0xbf60f02c + +#define MAX_PENDING_CTRL_PACKET (MAX_CTRL_QUEUE_LEN-10) + +#define WIMAX_MAX_MTU (MTU_SIZE + ETH_HLEN) +#define AUTO_LINKUP_ENABLE 0x2 +#define AUTO_SYNC_DISABLE 0x1 +#define AUTO_FIRM_DOWNLOAD 0x1 +#define SETTLE_DOWN_TIME 50 + +#define HOST_BUS_SUSPEND_BIT 16 + +#define IDLE_MESSAGE 0x81 + +#define MIPS_CLOCK_133MHz 1 + +#define TARGET_CAN_GO_TO_IDLE_MODE 2 +#define TARGET_CAN_NOT_GO_TO_IDLE_MODE 3 +#define IDLE_MODE_PAYLOAD_LENGTH 8 + +#define IP_HEADER(Buffer) ((IPHeaderFormat *)(Buffer)) +#define IPV4 4 +#define IP_VERSION(byte) (((byte&0xF0)>>4)) + +#define SET_MAC_ADDRESS 193 +#define SET_MAC_ADDRESS_RESPONSE 236 + +#define IDLE_MODE_WAKEUP_PATTERN 0xd0ea1d1e +#define IDLE_MODE_WAKEUP_NOTIFIER_ADDRESS 0x1FC02FA8 +#define IDLE_MODE_MAX_RETRY_COUNT 1000 + +#define CONFIG_BEGIN_ADDR 0xBF60B000 + +#define FIRMWARE_BEGIN_ADDR 0xBFC00000 + +#define INVALID_QUEUE_INDEX NO_OF_QUEUES + +#define INVALID_PID ((pid_t)-1) +#define DDR_80_MHZ 0 +#define DDR_100_MHZ 1 +#define DDR_120_MHZ 2 /* Additional Frequency for T3LP */ +#define DDR_133_MHZ 3 +#define DDR_140_MHZ 4 /* Not Used (Reserved for future) */ +#define DDR_160_MHZ 5 /* Additional Frequency for T3LP */ +#define DDR_180_MHZ 6 /* Not Used (Reserved for future) */ +#define DDR_200_MHZ 7 /* Not Used (Reserved for future) */ + +#define MIPS_200_MHZ 0 +#define MIPS_160_MHZ 1 + +#define PLL_800_MHZ 0 +#define PLL_266_MHZ 1 + +#define DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING 0 +#define DEVICE_POWERSAVE_MODE_AS_PMU_CLOCK_GATING 1 +#define DEVICE_POWERSAVE_MODE_AS_PMU_SHUTDOWN 2 +#define DEVICE_POWERSAVE_MODE_AS_RESERVED 3 +#define DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE 4 + + +#define EEPROM_REJECT_REG_1 0x0f003018 +#define EEPROM_REJECT_REG_2 0x0f00301c +#define EEPROM_REJECT_REG_3 0x0f003008 +#define EEPROM_REJECT_REG_4 0x0f003020 +#define EEPROM_REJECT_MASK 0x0fffffff +#define VSG_MODE 0x3 + +/* Idle Mode Related Registers */ +#define DEBUG_INTERRUPT_GENERATOR_REGISTOR 0x0F00007C +#define SW_ABORT_IDLEMODE_LOC 0x0FF01FFC + +#define SW_ABORT_IDLEMODE_PATTERN 0xd0ea1d1e +#define DEVICE_INT_OUT_EP_REG0 0x0F011870 +#define DEVICE_INT_OUT_EP_REG1 0x0F011874 + +#define BIN_FILE "/lib/firmware/macxvi200.bin" +#define CFG_FILE "/lib/firmware/macxvi.cfg" +#define SF_MAX_ALLOWED_PACKETS_TO_BACKUP 128 +#define MIN_VAL(x, y) ((x) < (y) ? (x) : (y)) +#define MAC_ADDRESS_SIZE 6 +#define EEPROM_COMMAND_Q_REG 0x0F003018 +#define EEPROM_READ_DATA_Q_REG 0x0F003020 +#define CHIP_ID_REG 0x0F000000 +#define GPIO_MODE_REG 0x0F000034 +#define GPIO_OUTPUT_REG 0x0F00003C +#define WIMAX_MAX_ALLOWED_RATE (1024*1024*50) + +#define T3 0xbece0300 +#define TARGET_SFID_TXDESC_MAP_LOC 0xBFFFF400 + +#define RWM_READ 0 +#define RWM_WRITE 1 + +#define T3LPB 0xbece3300 +#define BCS220_2 0xbece3311 +#define BCS220_2BC 0xBECE3310 +#define BCS250_BC 0xbece3301 +#define BCS220_3 0xbece3321 + + +#define HPM_CONFIG_LDO145 0x0F000D54 +#define HPM_CONFIG_MSW 0x0F000D58 + +#define T3B 0xbece0310 +enum bcm_nvm_type { + NVM_AUTODETECT = 0, + NVM_EEPROM, + NVM_FLASH, + NVM_UNKNOWN +}; + +enum bcm_pmu_modes { + HYBRID_MODE_7C = 0, + INTERNAL_MODE_6 = 1, + HYBRID_MODE_6 = 2 +}; + +#define MAX_RDM_WRM_RETIRES 1 + +enum eAbortPattern { + ABORT_SHUTDOWN_MODE = 1, + ABORT_IDLE_REG = 1, + ABORT_IDLE_MODE = 2, + ABORT_IDLE_SYNCDOWN = 3 +}; + + +/* Offsets used by driver in skb cb variable */ +#define SKB_CB_CLASSIFICATION_OFFSET 0 +#define SKB_CB_LATENCY_OFFSET 1 +#define SKB_CB_TCPACK_OFFSET 2 + +#endif /* __MACROS_H__ */ diff --git a/drivers/staging/bcm/Makefile b/drivers/staging/bcm/Makefile new file mode 100644 index 00000000000..652b7f87737 --- /dev/null +++ b/drivers/staging/bcm/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for Beceem USB Wimax card +# + +obj-$(CONFIG_BCM_WIMAX) += bcm_wimax.o + +bcm_wimax-y := InterfaceDld.o InterfaceIdleMode.o InterfaceInit.o InterfaceRx.o \ + InterfaceIsr.o InterfaceMisc.o InterfaceTx.o \ + CmHost.o IPv6Protocol.o Qos.o Transmit.o\ + Bcmnet.o DDRInit.o HandleControlPacket.o\ + LeakyBucket.o Misc.o sort.o Bcmchar.o hostmibs.o PHSModule.o\ + led_control.o nvm.o vendorspecificextn.o diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c new file mode 100644 index 00000000000..7b2fa0f4a2e --- /dev/null +++ b/drivers/staging/bcm/Misc.c @@ -0,0 +1,1580 @@ +#include "headers.h" + +static int BcmFileDownload(struct bcm_mini_adapter *Adapter, const char *path, unsigned int loc); +static void doPowerAutoCorrection(struct bcm_mini_adapter *psAdapter); +static void HandleShutDownModeRequest(struct bcm_mini_adapter *Adapter, PUCHAR pucBuffer); +static int bcm_parse_target_params(struct bcm_mini_adapter *Adapter); +static void beceem_protocol_reset(struct bcm_mini_adapter *Adapter); + +static void default_wimax_protocol_initialize(struct bcm_mini_adapter *Adapter) +{ + unsigned int uiLoopIndex; + + for (uiLoopIndex = 0; uiLoopIndex < NO_OF_QUEUES-1; uiLoopIndex++) { + Adapter->PackInfo[uiLoopIndex].uiThreshold = TX_PACKET_THRESHOLD; + Adapter->PackInfo[uiLoopIndex].uiMaxAllowedRate = MAX_ALLOWED_RATE; + Adapter->PackInfo[uiLoopIndex].uiMaxBucketSize = 20*1024*1024; + } + + Adapter->BEBucketSize = BE_BUCKET_SIZE; + Adapter->rtPSBucketSize = rtPS_BUCKET_SIZE; + Adapter->LinkStatus = SYNC_UP_REQUEST; + Adapter->TransferMode = IP_PACKET_ONLY_MODE; + Adapter->usBestEffortQueueIndex = -1; + return; +} + +int InitAdapter(struct bcm_mini_adapter *psAdapter) +{ + int i = 0; + int Status = STATUS_SUCCESS; + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Initialising Adapter = %p", psAdapter); + + if (psAdapter == NULL) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Adapter is NULL"); + return -EINVAL; + } + + sema_init(&psAdapter->NVMRdmWrmLock, 1); + sema_init(&psAdapter->rdmwrmsync, 1); + spin_lock_init(&psAdapter->control_queue_lock); + spin_lock_init(&psAdapter->txtransmitlock); + sema_init(&psAdapter->RxAppControlQueuelock, 1); + sema_init(&psAdapter->fw_download_sema, 1); + sema_init(&psAdapter->LowPowerModeSync, 1); + + for (i = 0; i < NO_OF_QUEUES; i++) + spin_lock_init(&psAdapter->PackInfo[i].SFQueueLock); + i = 0; + + init_waitqueue_head(&psAdapter->process_rx_cntrlpkt); + init_waitqueue_head(&psAdapter->tx_packet_wait_queue); + init_waitqueue_head(&psAdapter->process_read_wait_queue); + init_waitqueue_head(&psAdapter->ioctl_fw_dnld_wait_queue); + init_waitqueue_head(&psAdapter->lowpower_mode_wait_queue); + psAdapter->waiting_to_fw_download_done = TRUE; + psAdapter->fw_download_done = false; + + default_wimax_protocol_initialize(psAdapter); + for (i = 0; i < MAX_CNTRL_PKTS; i++) { + psAdapter->txctlpacket[i] = kmalloc(MAX_CNTL_PKT_SIZE, GFP_KERNEL); + if (!psAdapter->txctlpacket[i]) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "No More Cntl pkts got, max got is %d", i); + return -ENOMEM; + } + } + + if (AllocAdapterDsxBuffer(psAdapter)) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Failed to allocate DSX buffers"); + return -EINVAL; + } + + /* Initialize PHS interface */ + if (phs_init(&psAdapter->stBCMPhsContext, psAdapter) != 0) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "%s:%s:%d:Error PHS Init Failed=====>\n", __FILE__, __func__, __LINE__); + return -ENOMEM; + } + + Status = BcmAllocFlashCSStructure(psAdapter); + if (Status) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Memory Allocation for Flash structure failed"); + return Status; + } + + Status = vendorextnInit(psAdapter); + + if (STATUS_SUCCESS != Status) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Vendor Init Failed"); + return Status; + } + + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Adapter initialised"); + + return STATUS_SUCCESS; +} + +void AdapterFree(struct bcm_mini_adapter *Adapter) +{ + int count; + beceem_protocol_reset(Adapter); + vendorextnExit(Adapter); + + if (Adapter->control_packet_handler && !IS_ERR(Adapter->control_packet_handler)) + kthread_stop(Adapter->control_packet_handler); + + if (Adapter->transmit_packet_thread && !IS_ERR(Adapter->transmit_packet_thread)) + kthread_stop(Adapter->transmit_packet_thread); + + wake_up(&Adapter->process_read_wait_queue); + + if (Adapter->LEDInfo.led_thread_running & (BCM_LED_THREAD_RUNNING_ACTIVELY | BCM_LED_THREAD_RUNNING_INACTIVELY)) + kthread_stop(Adapter->LEDInfo.led_cntrl_threadid); + + unregister_networkdev(Adapter); + + /* FIXME: use proper wait_event and refcounting */ + while (atomic_read(&Adapter->ApplicationRunning)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Waiting for Application to close.. %d\n", atomic_read(&Adapter->ApplicationRunning)); + msleep(100); + } + unregister_control_device_interface(Adapter); + kfree(Adapter->pstargetparams); + + for (count = 0; count < MAX_CNTRL_PKTS; count++) + kfree(Adapter->txctlpacket[count]); + + FreeAdapterDsxBuffer(Adapter); + kfree(Adapter->pvInterfaceAdapter); + + /* Free the PHS Interface */ + PhsCleanup(&Adapter->stBCMPhsContext); + + BcmDeAllocFlashCSStructure(Adapter); + + free_netdev(Adapter->dev); +} + +static int create_worker_threads(struct bcm_mini_adapter *psAdapter) +{ + /* Rx Control Packets Processing */ + psAdapter->control_packet_handler = kthread_run((int (*)(void *)) + control_packet_handler, psAdapter, "%s-rx", DRV_NAME); + if (IS_ERR(psAdapter->control_packet_handler)) { + pr_notice(DRV_NAME ": could not create control thread\n"); + return PTR_ERR(psAdapter->control_packet_handler); + } + + /* Tx Thread */ + psAdapter->transmit_packet_thread = kthread_run((int (*)(void *)) + tx_pkt_handler, psAdapter, "%s-tx", DRV_NAME); + if (IS_ERR(psAdapter->transmit_packet_thread)) { + pr_notice(DRV_NAME ": could not creat transmit thread\n"); + kthread_stop(psAdapter->control_packet_handler); + return PTR_ERR(psAdapter->transmit_packet_thread); + } + return 0; +} + +static struct file *open_firmware_file(struct bcm_mini_adapter *Adapter, const char *path) +{ + struct file *flp = filp_open(path, O_RDONLY, S_IRWXU); + if (IS_ERR(flp)) { + pr_err(DRV_NAME "Unable To Open File %s, err %ld", path, PTR_ERR(flp)); + flp = NULL; + } + + if (Adapter->device_removed) + flp = NULL; + + return flp; +} + +/* Arguments: + * Logical Adapter + * Path to image file + * Download Address on the chip + */ +static int BcmFileDownload(struct bcm_mini_adapter *Adapter, const char *path, unsigned int loc) +{ + int errorno = 0; + struct file *flp = NULL; + struct timeval tv = {0}; + + flp = open_firmware_file(Adapter, path); + if (!flp) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Unable to Open %s\n", path); + return -ENOENT; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Opened file is = %s and length =0x%lx to be downloaded at =0x%x", path, (unsigned long)file_inode(flp)->i_size, loc); + do_gettimeofday(&tv); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "download start %lx", ((tv.tv_sec * 1000) + (tv.tv_usec / 1000))); + if (Adapter->bcm_file_download(Adapter->pvInterfaceAdapter, flp, loc)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Failed to download the firmware with error %x!!!", -EIO); + errorno = -EIO; + goto exit_download; + } + vfs_llseek(flp, 0, 0); + if (Adapter->bcm_file_readback_from_chip(Adapter->pvInterfaceAdapter, flp, loc)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Failed to read back firmware!"); + errorno = -EIO; + goto exit_download; + } + +exit_download: + filp_close(flp, NULL); + return errorno; +} + +/** + * @ingroup ctrl_pkt_functions + * This function copies the contents of given buffer + * to the control packet and queues it for transmission. + * @note Do not acquire the spinlock, as it it already acquired. + * @return SUCCESS/FAILURE. + * Arguments: + * Logical Adapter + * Control Packet Buffer + */ +int CopyBufferToControlPacket(struct bcm_mini_adapter *Adapter, void *ioBuffer) +{ + struct bcm_leader *pLeader = NULL; + int Status = 0; + unsigned char *ctrl_buff; + unsigned int pktlen = 0; + struct bcm_link_request *pLinkReq = NULL; + PUCHAR pucAddIndication = NULL; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "======>"); + if (!ioBuffer) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Got Null Buffer\n"); + return -EINVAL; + } + + pLinkReq = (struct bcm_link_request *)ioBuffer; + pLeader = (struct bcm_leader *)ioBuffer; /* ioBuffer Contains sw_Status and Payload */ + + if (Adapter->bShutStatus == TRUE && + pLinkReq->szData[0] == LINK_DOWN_REQ_PAYLOAD && + pLinkReq->szData[1] == LINK_SYNC_UP_SUBTYPE) { + + /* Got sync down in SHUTDOWN..we could not process this. */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "SYNC DOWN Request in Shut Down Mode..\n"); + return STATUS_FAILURE; + } + + if ((pLeader->Status == LINK_UP_CONTROL_REQ) && + ((pLinkReq->szData[0] == LINK_UP_REQ_PAYLOAD && + (pLinkReq->szData[1] == LINK_SYNC_UP_SUBTYPE)) || /* Sync Up Command */ + pLinkReq->szData[0] == NETWORK_ENTRY_REQ_PAYLOAD)) /* Net Entry Command */ { + + if (Adapter->LinkStatus > PHY_SYNC_ACHIVED) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "LinkStatus is Greater than PHY_SYN_ACHIEVED"); + return STATUS_FAILURE; + } + + if (Adapter->bShutStatus == TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "SYNC UP IN SHUTDOWN..Device WakeUp\n"); + if (Adapter->bTriedToWakeUpFromlowPowerMode == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Waking up for the First Time..\n"); + Adapter->usIdleModePattern = ABORT_SHUTDOWN_MODE; /* change it to 1 for current support. */ + Adapter->bWakeUpDevice = TRUE; + wake_up(&Adapter->process_rx_cntrlpkt); + Status = wait_event_interruptible_timeout(Adapter->lowpower_mode_wait_queue, !Adapter->bShutStatus, (5 * HZ)); + + if (Status == -ERESTARTSYS) + return Status; + + if (Adapter->bShutStatus) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Shutdown Mode Wake up Failed - No Wake Up Received\n"); + return STATUS_FAILURE; + } + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Wakeup has been tried already...\n"); + } + } + } + + if (Adapter->IdleMode == TRUE) { + /* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Device is in Idle mode ... hence\n"); */ + if (pLeader->Status == LINK_UP_CONTROL_REQ || pLeader->Status == 0x80 || + pLeader->Status == CM_CONTROL_NEWDSX_MULTICLASSIFIER_REQ) { + + if ((pLeader->Status == LINK_UP_CONTROL_REQ) && (pLinkReq->szData[0] == LINK_DOWN_REQ_PAYLOAD)) { + if ((pLinkReq->szData[1] == LINK_SYNC_DOWN_SUBTYPE)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Link Down Sent in Idle Mode\n"); + Adapter->usIdleModePattern = ABORT_IDLE_SYNCDOWN; /* LINK DOWN sent in Idle Mode */ + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "ABORT_IDLE_MODE pattern is being written\n"); + Adapter->usIdleModePattern = ABORT_IDLE_REG; + } + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "ABORT_IDLE_MODE pattern is being written\n"); + Adapter->usIdleModePattern = ABORT_IDLE_MODE; + } + + /*Setting bIdleMode_tx_from_host to TRUE to indicate LED control thread to represent + * the wake up from idlemode is from host + */ + /* Adapter->LEDInfo.bIdleMode_tx_from_host = TRUE; */ + Adapter->bWakeUpDevice = TRUE; + wake_up(&Adapter->process_rx_cntrlpkt); + + /* We should not send DREG message down while in idlemode. */ + if (LINK_DOWN_REQ_PAYLOAD == pLinkReq->szData[0]) + return STATUS_SUCCESS; + + Status = wait_event_interruptible_timeout(Adapter->lowpower_mode_wait_queue, !Adapter->IdleMode, (5 * HZ)); + + if (Status == -ERESTARTSYS) + return Status; + + if (Adapter->IdleMode) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Idle Mode Wake up Failed - No Wake Up Received\n"); + return STATUS_FAILURE; + } + } else { + return STATUS_SUCCESS; + } + } + + /* The Driver has to send control messages with a particular VCID */ + pLeader->Vcid = VCID_CONTROL_PACKET; /* VCID for control packet. */ + + /* Allocate skb for Control Packet */ + pktlen = pLeader->PLength; + ctrl_buff = (char *)Adapter->txctlpacket[atomic_read(&Adapter->index_wr_txcntrlpkt)%MAX_CNTRL_PKTS]; + + if (!ctrl_buff) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "mem allocation Failed"); + return -ENOMEM; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Control packet to be taken =%d and address is =%pincoming address is =%p and packet len=%x", + atomic_read(&Adapter->index_wr_txcntrlpkt), ctrl_buff, ioBuffer, pktlen); + + if (pLeader) { + if ((pLeader->Status == 0x80) || + (pLeader->Status == CM_CONTROL_NEWDSX_MULTICLASSIFIER_REQ)) { + /* + * Restructure the DSX message to handle Multiple classifier Support + * Write the Service Flow param Structures directly to the target + * and embed the pointers in the DSX messages sent to target. + */ + /* Lets store the current length of the control packet we are transmitting */ + pucAddIndication = (PUCHAR)ioBuffer + LEADER_SIZE; + pktlen = pLeader->PLength; + Status = StoreCmControlResponseMessage(Adapter, pucAddIndication, &pktlen); + if (Status != 1) { + ClearTargetDSXBuffer(Adapter, ((struct bcm_add_indication_alt *)pucAddIndication)->u16TID, false); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, " Error Restoring The DSX Control Packet. Dsx Buffers on Target may not be Setup Properly "); + return STATUS_FAILURE; + } + /* + * update the leader to use the new length + * The length of the control packet is length of message being sent + Leader length + */ + pLeader->PLength = pktlen; + } + } + + if (pktlen + LEADER_SIZE > MAX_CNTL_PKT_SIZE) + return -EINVAL; + + memset(ctrl_buff, 0, pktlen+LEADER_SIZE); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Copying the Control Packet Buffer with length=%d\n", pLeader->PLength); + *(struct bcm_leader *)ctrl_buff = *pLeader; + memcpy(ctrl_buff + LEADER_SIZE, ((PUCHAR)ioBuffer + LEADER_SIZE), pLeader->PLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Enqueuing the Control Packet"); + + /* Update the statistics counters */ + spin_lock_bh(&Adapter->PackInfo[HiPriority].SFQueueLock); + Adapter->PackInfo[HiPriority].uiCurrentBytesOnHost += pLeader->PLength; + Adapter->PackInfo[HiPriority].uiCurrentPacketsOnHost++; + atomic_inc(&Adapter->TotalPacketCount); + spin_unlock_bh(&Adapter->PackInfo[HiPriority].SFQueueLock); + Adapter->PackInfo[HiPriority].bValid = TRUE; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "CurrBytesOnHost: %x bValid: %x", + Adapter->PackInfo[HiPriority].uiCurrentBytesOnHost, + Adapter->PackInfo[HiPriority].bValid); + Status = STATUS_SUCCESS; + /*Queue the packet for transmission */ + atomic_inc(&Adapter->index_wr_txcntrlpkt); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Calling transmit_packets"); + atomic_set(&Adapter->TxPktAvail, 1); + wake_up(&Adapter->tx_packet_wait_queue); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<===="); + return Status; +} + +/****************************************************************** +* Function - LinkMessage() +* +* Description - This function builds the Sync-up and Link-up request +* packet messages depending on the device Link status. +* +* Parameters - Adapter: Pointer to the Adapter structure. +* +* Returns - None. +*******************************************************************/ +void LinkMessage(struct bcm_mini_adapter *Adapter) +{ + struct bcm_link_request *pstLinkRequest = NULL; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "=====>"); + if (Adapter->LinkStatus == SYNC_UP_REQUEST && Adapter->AutoSyncup) { + pstLinkRequest = kzalloc(sizeof(struct bcm_link_request), GFP_ATOMIC); + if (!pstLinkRequest) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "Can not allocate memory for Link request!"); + return; + } + /* sync up request... */ + Adapter->LinkStatus = WAIT_FOR_SYNC; /* current link status */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "Requesting For SyncUp..."); + pstLinkRequest->szData[0] = LINK_UP_REQ_PAYLOAD; + pstLinkRequest->szData[1] = LINK_SYNC_UP_SUBTYPE; + pstLinkRequest->Leader.Status = LINK_UP_CONTROL_REQ; + pstLinkRequest->Leader.PLength = sizeof(ULONG); + Adapter->bSyncUpRequestSent = TRUE; + + } else if (Adapter->LinkStatus == PHY_SYNC_ACHIVED && Adapter->AutoLinkUp) { + pstLinkRequest = kzalloc(sizeof(struct bcm_link_request), GFP_ATOMIC); + if (!pstLinkRequest) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "Can not allocate memory for Link request!"); + return; + } + /* LINK_UP_REQUEST */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "Requesting For LinkUp..."); + pstLinkRequest->szData[0] = LINK_UP_REQ_PAYLOAD; + pstLinkRequest->szData[1] = LINK_NET_ENTRY; + pstLinkRequest->Leader.Status = LINK_UP_CONTROL_REQ; + pstLinkRequest->Leader.PLength = sizeof(ULONG); + } + if (pstLinkRequest) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "Calling CopyBufferToControlPacket"); + CopyBufferToControlPacket(Adapter, pstLinkRequest); + kfree(pstLinkRequest); + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LINK_UP_MSG, DBG_LVL_ALL, "LinkMessage <====="); + return; +} + +/********************************************************************** +* Function - StatisticsResponse() +* +* Description - This function handles the Statistics response packet. +* +* Parameters - Adapter : Pointer to the Adapter structure. +* - pvBuffer: Starting address of Statistic response data. +* +* Returns - None. +************************************************************************/ +void StatisticsResponse(struct bcm_mini_adapter *Adapter, void *pvBuffer) +{ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "%s====>", __func__); + Adapter->StatisticsPointer = ntohl(*(__be32 *)pvBuffer); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Stats at %x", (unsigned int)Adapter->StatisticsPointer); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "%s <====", __func__); + return; +} + +/********************************************************************** +* Function - LinkControlResponseMessage() +* +* Description - This function handles the Link response packets. +* +* Parameters - Adapter : Pointer to the Adapter structure. +* - pucBuffer: Starting address of Link response data. +* +* Returns - None. +***********************************************************************/ +void LinkControlResponseMessage(struct bcm_mini_adapter *Adapter, PUCHAR pucBuffer) +{ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "=====>"); + + if (*pucBuffer == LINK_UP_ACK) { + switch (*(pucBuffer+1)) { + case PHY_SYNC_ACHIVED: /* SYNCed UP */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "PHY_SYNC_ACHIVED"); + + if (Adapter->LinkStatus == LINKUP_DONE) + beceem_protocol_reset(Adapter); + + Adapter->usBestEffortQueueIndex = INVALID_QUEUE_INDEX; + Adapter->LinkStatus = PHY_SYNC_ACHIVED; + + if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { + Adapter->DriverState = NO_NETWORK_ENTRY; + wake_up(&Adapter->LEDInfo.notify_led_event); + } + + LinkMessage(Adapter); + break; + + case LINKUP_DONE: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "LINKUP_DONE"); + Adapter->LinkStatus = LINKUP_DONE; + Adapter->bPHSEnabled = *(pucBuffer+3); + Adapter->bETHCSEnabled = *(pucBuffer+4) & ETH_CS_MASK; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "PHS Support Status Received In LinkUp Ack : %x\n", Adapter->bPHSEnabled); + + if ((false == Adapter->bShutStatus) && (false == Adapter->IdleMode)) { + if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { + Adapter->DriverState = NORMAL_OPERATION; + wake_up(&Adapter->LEDInfo.notify_led_event); + } + } + LinkMessage(Adapter); + break; + + case WAIT_FOR_SYNC: + /* + * Driver to ignore the DREG_RECEIVED + * WiMAX Application should handle this Message + */ + /* Adapter->liTimeSinceLastNetEntry = 0; */ + Adapter->LinkUpStatus = 0; + Adapter->LinkStatus = 0; + Adapter->usBestEffortQueueIndex = INVALID_QUEUE_INDEX; + Adapter->bTriedToWakeUpFromlowPowerMode = false; + Adapter->IdleMode = false; + beceem_protocol_reset(Adapter); + + break; + case LINK_SHUTDOWN_REQ_FROM_FIRMWARE: + case COMPLETE_WAKE_UP_NOTIFICATION_FRM_FW: + { + HandleShutDownModeRequest(Adapter, pucBuffer); + } + break; + default: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "default case:LinkResponse %x", *(pucBuffer + 1)); + break; + } + } else if (SET_MAC_ADDRESS_RESPONSE == *pucBuffer) { + PUCHAR puMacAddr = (pucBuffer + 1); + Adapter->LinkStatus = SYNC_UP_REQUEST; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "MAC address response, sending SYNC_UP"); + LinkMessage(Adapter); + memcpy(Adapter->dev->dev_addr, puMacAddr, MAC_ADDRESS_SIZE); + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "%s <=====", __func__); + return; +} + +void SendIdleModeResponse(struct bcm_mini_adapter *Adapter) +{ + int status = 0, NVMAccess = 0, lowPwrAbortMsg = 0; + struct timeval tv; + struct bcm_link_request stIdleResponse = {{0} }; + memset(&tv, 0, sizeof(tv)); + stIdleResponse.Leader.Status = IDLE_MESSAGE; + stIdleResponse.Leader.PLength = IDLE_MODE_PAYLOAD_LENGTH; + stIdleResponse.szData[0] = GO_TO_IDLE_MODE_PAYLOAD; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, " ============>"); + + /********************************* + *down_trylock - + * if [ semaphore is available ] + * acquire semaphone and return value 0 ; + * else + * return non-zero value ; + * + ***********************************/ + + NVMAccess = down_trylock(&Adapter->NVMRdmWrmLock); + lowPwrAbortMsg = down_trylock(&Adapter->LowPowerModeSync); + + + if ((NVMAccess || lowPwrAbortMsg || atomic_read(&Adapter->TotalPacketCount)) && + (Adapter->ulPowerSaveMode != DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE)) { + + if (!NVMAccess) + up(&Adapter->NVMRdmWrmLock); + + if (!lowPwrAbortMsg) + up(&Adapter->LowPowerModeSync); + + stIdleResponse.szData[1] = TARGET_CAN_NOT_GO_TO_IDLE_MODE; /* NACK- device access is going on. */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "HOST IS NACKING Idle mode To F/W!!!!!!!!"); + Adapter->bPreparingForLowPowerMode = false; + } else { + stIdleResponse.szData[1] = TARGET_CAN_GO_TO_IDLE_MODE; /* 2; Idle ACK */ + Adapter->StatisticsPointer = 0; + + /* Wait for the LED to TURN OFF before sending ACK response */ + if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { + int iRetVal = 0; + + /* Wake the LED Thread with IDLEMODE_ENTER State */ + Adapter->DriverState = LOWPOWER_MODE_ENTER; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "LED Thread is Running..Hence Setting LED Event as IDLEMODE_ENTER jiffies:%ld", jiffies); + wake_up(&Adapter->LEDInfo.notify_led_event); + + /* Wait for 1 SEC for LED to OFF */ + iRetVal = wait_event_timeout(Adapter->LEDInfo.idleModeSyncEvent, Adapter->LEDInfo.bIdle_led_off, msecs_to_jiffies(1000)); + + /* If Timed Out to Sync IDLE MODE Enter, do IDLE mode Exit and Send NACK to device */ + if (iRetVal <= 0) { + stIdleResponse.szData[1] = TARGET_CAN_NOT_GO_TO_IDLE_MODE; /* NACK- device access is going on. */ + Adapter->DriverState = NORMAL_OPERATION; + wake_up(&Adapter->LEDInfo.notify_led_event); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "NACKING Idle mode as time out happen from LED side!!!!!!!!"); + } + } + + if (stIdleResponse.szData[1] == TARGET_CAN_GO_TO_IDLE_MODE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "ACKING IDLE MODE !!!!!!!!!"); + down(&Adapter->rdmwrmsync); + Adapter->bPreparingForLowPowerMode = TRUE; + up(&Adapter->rdmwrmsync); + /* Killing all URBS. */ + if (Adapter->bDoSuspend == TRUE) + Bcm_kill_all_URBs((struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter)); + } else { + Adapter->bPreparingForLowPowerMode = false; + } + + if (!NVMAccess) + up(&Adapter->NVMRdmWrmLock); + + if (!lowPwrAbortMsg) + up(&Adapter->LowPowerModeSync); + } + + status = CopyBufferToControlPacket(Adapter, &stIdleResponse); + if ((status != STATUS_SUCCESS)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "fail to send the Idle mode Request\n"); + Adapter->bPreparingForLowPowerMode = false; + StartInterruptUrb((struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter)); + } + do_gettimeofday(&tv); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_RX, RX_DPC, DBG_LVL_ALL, "IdleMode Msg submitter to Q :%ld ms", tv.tv_sec * 1000 + tv.tv_usec / 1000); +} + +/****************************************************************** +* Function - DumpPackInfo() +* +* Description - This function dumps the all Queue(PackInfo[]) details. +* +* Parameters - Adapter: Pointer to the Adapter structure. +* +* Returns - None. +*******************************************************************/ +void DumpPackInfo(struct bcm_mini_adapter *Adapter) +{ + unsigned int uiLoopIndex = 0; + unsigned int uiIndex = 0; + unsigned int uiClsfrIndex = 0; + struct bcm_classifier_rule *pstClassifierEntry = NULL; + + for (uiLoopIndex = 0; uiLoopIndex < NO_OF_QUEUES; uiLoopIndex++) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "*********** Showing Details Of Queue %d***** ******", uiLoopIndex); + if (false == Adapter->PackInfo[uiLoopIndex].bValid) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "bValid is false for %X index\n", uiLoopIndex); + continue; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, " Dumping SF Rule Entry For SFID %lX\n", Adapter->PackInfo[uiLoopIndex].ulSFID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, " ucDirection %X\n", Adapter->PackInfo[uiLoopIndex].ucDirection); + + if (Adapter->PackInfo[uiLoopIndex].ucIpVersion == IPV6) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Ipv6 Service Flow\n"); + else + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Ipv4 Service Flow\n"); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "SF Traffic Priority %X\n", Adapter->PackInfo[uiLoopIndex].u8TrafficPriority); + + for (uiClsfrIndex = 0; uiClsfrIndex < MAX_CLASSIFIERS; uiClsfrIndex++) { + pstClassifierEntry = &Adapter->astClassifierTable[uiClsfrIndex]; + if (!pstClassifierEntry->bUsed) + continue; + + if (pstClassifierEntry->ulSFID != Adapter->PackInfo[uiLoopIndex].ulSFID) + continue; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tDumping Classifier Rule Entry For Index: %X Classifier Rule ID : %X\n", uiClsfrIndex, pstClassifierEntry->uiClassifierRuleIndex); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tDumping Classifier Rule Entry For Index: %X usVCID_Value : %X\n", uiClsfrIndex, pstClassifierEntry->usVCID_Value); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tDumping Classifier Rule Entry For Index: %X bProtocolValid : %X\n", uiClsfrIndex, pstClassifierEntry->bProtocolValid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tDumping Classifier Rule Entry For Index: %X bTOSValid : %X\n", uiClsfrIndex, pstClassifierEntry->bTOSValid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tDumping Classifier Rule Entry For Index: %X bDestIpValid : %X\n", uiClsfrIndex, pstClassifierEntry->bDestIpValid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tDumping Classifier Rule Entry For Index: %X bSrcIpValid : %X\n", uiClsfrIndex, pstClassifierEntry->bSrcIpValid); + + for (uiIndex = 0; uiIndex < MAX_PORT_RANGE; uiIndex++) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tusSrcPortRangeLo:%X\n", pstClassifierEntry->usSrcPortRangeLo[uiIndex]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tusSrcPortRangeHi:%X\n", pstClassifierEntry->usSrcPortRangeHi[uiIndex]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tusDestPortRangeLo:%X\n", pstClassifierEntry->usDestPortRangeLo[uiIndex]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tusDestPortRangeHi:%X\n", pstClassifierEntry->usDestPortRangeHi[uiIndex]); + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tucIPSourceAddressLength : 0x%x\n", pstClassifierEntry->ucIPSourceAddressLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tucIPDestinationAddressLength : 0x%x\n", pstClassifierEntry->ucIPDestinationAddressLength); + for (uiIndex = 0; uiIndex < pstClassifierEntry->ucIPSourceAddressLength; uiIndex++) { + if (Adapter->PackInfo[uiLoopIndex].ucIpVersion == IPV6) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tIpv6 ulSrcIpAddr :\n"); + DumpIpv6Address(pstClassifierEntry->stSrcIpAddress.ulIpv6Addr); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tIpv6 ulSrcIpMask :\n"); + DumpIpv6Address(pstClassifierEntry->stSrcIpAddress.ulIpv6Mask); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tulSrcIpAddr:%lX\n", pstClassifierEntry->stSrcIpAddress.ulIpv4Addr[uiIndex]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tulSrcIpMask:%lX\n", pstClassifierEntry->stSrcIpAddress.ulIpv4Mask[uiIndex]); + } + } + + for (uiIndex = 0; uiIndex < pstClassifierEntry->ucIPDestinationAddressLength; uiIndex++) { + if (Adapter->PackInfo[uiLoopIndex].ucIpVersion == IPV6) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tIpv6 ulDestIpAddr :\n"); + DumpIpv6Address(pstClassifierEntry->stDestIpAddress.ulIpv6Addr); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tIpv6 ulDestIpMask :\n"); + DumpIpv6Address(pstClassifierEntry->stDestIpAddress.ulIpv6Mask); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tulDestIpAddr:%lX\n", pstClassifierEntry->stDestIpAddress.ulIpv4Addr[uiIndex]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tulDestIpMask:%lX\n", pstClassifierEntry->stDestIpAddress.ulIpv4Mask[uiIndex]); + } + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tucProtocol:0x%X\n", pstClassifierEntry->ucProtocol[0]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\tu8ClassifierRulePriority:%X\n", pstClassifierEntry->u8ClassifierRulePriority); + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "ulSFID:%lX\n", Adapter->PackInfo[uiLoopIndex].ulSFID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "usVCID_Value:%X\n", Adapter->PackInfo[uiLoopIndex].usVCID_Value); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "PhsEnabled: 0x%X\n", Adapter->PackInfo[uiLoopIndex].bHeaderSuppressionEnabled); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiThreshold:%X\n", Adapter->PackInfo[uiLoopIndex].uiThreshold); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "bValid:%X\n", Adapter->PackInfo[uiLoopIndex].bValid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "bActive:%X\n", Adapter->PackInfo[uiLoopIndex].bActive); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "ActivateReqSent: %x", Adapter->PackInfo[uiLoopIndex].bActivateRequestSent); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "u8QueueType:%X\n", Adapter->PackInfo[uiLoopIndex].u8QueueType); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiMaxBucketSize:%X\n", Adapter->PackInfo[uiLoopIndex].uiMaxBucketSize); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiPerSFTxResourceCount:%X\n", atomic_read(&Adapter->PackInfo[uiLoopIndex].uiPerSFTxResourceCount)); + /* DumpDebug(DUMP_INFO,("bCSSupport:%X\n",Adapter->PackInfo[uiLoopIndex].bCSSupport)); */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "CurrQueueDepthOnTarget: %x\n", Adapter->PackInfo[uiLoopIndex].uiCurrentQueueDepthOnTarget); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiCurrentBytesOnHost:%X\n", Adapter->PackInfo[uiLoopIndex].uiCurrentBytesOnHost); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiCurrentPacketsOnHost:%X\n", Adapter->PackInfo[uiLoopIndex].uiCurrentPacketsOnHost); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiDroppedCountBytes:%X\n", Adapter->PackInfo[uiLoopIndex].uiDroppedCountBytes); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiDroppedCountPackets:%X\n", Adapter->PackInfo[uiLoopIndex].uiDroppedCountPackets); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiSentBytes:%X\n", Adapter->PackInfo[uiLoopIndex].uiSentBytes); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiSentPackets:%X\n", Adapter->PackInfo[uiLoopIndex].uiSentPackets); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiCurrentDrainRate:%X\n", Adapter->PackInfo[uiLoopIndex].uiCurrentDrainRate); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiThisPeriodSentBytes:%X\n", Adapter->PackInfo[uiLoopIndex].uiThisPeriodSentBytes); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "liDrainCalculated:%llX\n", Adapter->PackInfo[uiLoopIndex].liDrainCalculated); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiCurrentTokenCount:%X\n", Adapter->PackInfo[uiLoopIndex].uiCurrentTokenCount); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "liLastUpdateTokenAt:%llX\n", Adapter->PackInfo[uiLoopIndex].liLastUpdateTokenAt); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiMaxAllowedRate:%X\n", Adapter->PackInfo[uiLoopIndex].uiMaxAllowedRate); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiPendedLast:%X\n", Adapter->PackInfo[uiLoopIndex].uiPendedLast); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "NumOfPacketsSent:%X\n", Adapter->PackInfo[uiLoopIndex].NumOfPacketsSent); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Direction: %x\n", Adapter->PackInfo[uiLoopIndex].ucDirection); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "CID: %x\n", Adapter->PackInfo[uiLoopIndex].usCID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "ProtocolValid: %x\n", Adapter->PackInfo[uiLoopIndex].bProtocolValid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "TOSValid: %x\n", Adapter->PackInfo[uiLoopIndex].bTOSValid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "DestIpValid: %x\n", Adapter->PackInfo[uiLoopIndex].bDestIpValid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "SrcIpValid: %x\n", Adapter->PackInfo[uiLoopIndex].bSrcIpValid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "ActiveSet: %x\n", Adapter->PackInfo[uiLoopIndex].bActiveSet); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "AdmittedSet: %x\n", Adapter->PackInfo[uiLoopIndex].bAdmittedSet); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "AuthzSet: %x\n", Adapter->PackInfo[uiLoopIndex].bAuthorizedSet); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "ClassifyPrority: %x\n", Adapter->PackInfo[uiLoopIndex].bClassifierPriority); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiMaxLatency: %x\n", Adapter->PackInfo[uiLoopIndex].uiMaxLatency); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, + DBG_LVL_ALL, "ServiceClassName: %*ph\n", + 4, Adapter->PackInfo[uiLoopIndex]. + ucServiceClassName); +/* BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "bHeaderSuppressionEnabled :%X\n", Adapter->PackInfo[uiLoopIndex].bHeaderSuppressionEnabled); + * BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiTotalTxBytes:%X\n", Adapter->PackInfo[uiLoopIndex].uiTotalTxBytes); + * BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiTotalRxBytes:%X\n", Adapter->PackInfo[uiLoopIndex].uiTotalRxBytes); + * DumpDebug(DUMP_INFO,(" uiRanOutOfResCount:%X\n",Adapter->PackInfo[uiLoopIndex].uiRanOutOfResCount)); + */ + } + + for (uiLoopIndex = 0; uiLoopIndex < MIBS_MAX_HIST_ENTRIES; uiLoopIndex++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Adapter->aRxPktSizeHist[%x] = %x\n", uiLoopIndex, Adapter->aRxPktSizeHist[uiLoopIndex]); + + for (uiLoopIndex = 0; uiLoopIndex < MIBS_MAX_HIST_ENTRIES; uiLoopIndex++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Adapter->aTxPktSizeHist[%x] = %x\n", uiLoopIndex, Adapter->aTxPktSizeHist[uiLoopIndex]); + + return; +} + +int reset_card_proc(struct bcm_mini_adapter *ps_adapter) +{ + int retval = STATUS_SUCCESS; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + struct bcm_interface_adapter *psIntfAdapter = NULL; + unsigned int value = 0, uiResetValue = 0; + int bytes; + + psIntfAdapter = ((struct bcm_interface_adapter *)(ps_adapter->pvInterfaceAdapter)); + ps_adapter->bDDRInitDone = false; + + if (ps_adapter->chip_id >= T3LPB) { + /* SYS_CFG register is write protected hence for modifying this reg value, it should be read twice before */ + rdmalt(ps_adapter, SYS_CFG, &value, sizeof(value)); + rdmalt(ps_adapter, SYS_CFG, &value, sizeof(value)); + + /* making bit[6...5] same as was before f/w download. this setting force the h/w to */ + /* re-populated the SP RAM area with the string descriptor. */ + value = value | (ps_adapter->syscfgBefFwDld & 0x00000060); + wrmalt(ps_adapter, SYS_CFG, &value, sizeof(value)); + } + + /* killing all submitted URBs. */ + psIntfAdapter->psAdapter->StopAllXaction = TRUE; + Bcm_kill_all_URBs(psIntfAdapter); + /* Reset the UMA-B Device */ + if (ps_adapter->chip_id >= T3LPB) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Resetting UMA-B\n"); + retval = usb_reset_device(psIntfAdapter->udev); + psIntfAdapter->psAdapter->StopAllXaction = false; + + if (retval != STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reset failed with ret value :%d", retval); + goto err_exit; + } + + if (ps_adapter->chip_id == BCS220_2 || + ps_adapter->chip_id == BCS220_2BC || + ps_adapter->chip_id == BCS250_BC || + ps_adapter->chip_id == BCS220_3) { + + bytes = rdmalt(ps_adapter, HPM_CONFIG_LDO145, &value, sizeof(value)); + if (bytes < 0) { + retval = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "read failed with status :%d", retval); + goto err_exit; + } + /* setting 0th bit */ + value |= (1<<0); + retval = wrmalt(ps_adapter, HPM_CONFIG_LDO145, &value, sizeof(value)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "write failed with status :%d", retval); + goto err_exit; + } + } + } else { + bytes = rdmalt(ps_adapter, 0x0f007018, &value, sizeof(value)); + if (bytes < 0) { + retval = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "read failed with status :%d", retval); + goto err_exit; + } + value &= (~(1<<16)); + retval = wrmalt(ps_adapter, 0x0f007018, &value, sizeof(value)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "write failed with status :%d", retval); + goto err_exit; + } + + /* Toggling the GPIO 8, 9 */ + value = 0; + retval = wrmalt(ps_adapter, GPIO_OUTPUT_REGISTER, &value, sizeof(value)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "write failed with status :%d", retval); + goto err_exit; + } + value = 0x300; + retval = wrmalt(ps_adapter, GPIO_MODE_REGISTER, &value, sizeof(value)); + if (retval < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "write failed with status :%d", retval); + goto err_exit; + } + mdelay(50); + } + + /* ps_adapter->downloadDDR = false; */ + if (ps_adapter->bFlashBoot) { + /* In flash boot mode MIPS state register has reverse polarity. + * So just or with setting bit 30. + * Make the MIPS in Reset state. + */ + rdmalt(ps_adapter, CLOCK_RESET_CNTRL_REG_1, &uiResetValue, sizeof(uiResetValue)); + uiResetValue |= (1<<30); + wrmalt(ps_adapter, CLOCK_RESET_CNTRL_REG_1, &uiResetValue, sizeof(uiResetValue)); + } + + if (ps_adapter->chip_id >= T3LPB) { + uiResetValue = 0; + /* + * WA for SYSConfig Issue. + * Read SYSCFG Twice to make it writable. + */ + rdmalt(ps_adapter, SYS_CFG, &uiResetValue, sizeof(uiResetValue)); + if (uiResetValue & (1<<4)) { + uiResetValue = 0; + rdmalt(ps_adapter, SYS_CFG, &uiResetValue, sizeof(uiResetValue)); /* 2nd read to make it writable. */ + uiResetValue &= (~(1<<4)); + wrmalt(ps_adapter, SYS_CFG, &uiResetValue, sizeof(uiResetValue)); + } + } + uiResetValue = 0; + wrmalt(ps_adapter, 0x0f01186c, &uiResetValue, sizeof(uiResetValue)); + +err_exit: + psIntfAdapter->psAdapter->StopAllXaction = false; + return retval; +} + +int run_card_proc(struct bcm_mini_adapter *ps_adapter) +{ + int status = STATUS_SUCCESS; + int bytes; + + unsigned int value = 0; + { + bytes = rdmalt(ps_adapter, CLOCK_RESET_CNTRL_REG_1, &value, sizeof(value)); + if (bytes < 0) { + status = bytes; + BCM_DEBUG_PRINT(ps_adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "%s:%d\n", __func__, __LINE__); + return status; + } + + if (ps_adapter->bFlashBoot) + value &= (~(1<<30)); + else + value |= (1<<30); + + if (wrmalt(ps_adapter, CLOCK_RESET_CNTRL_REG_1, &value, sizeof(value)) < 0) { + BCM_DEBUG_PRINT(ps_adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "%s:%d\n", __func__, __LINE__); + return STATUS_FAILURE; + } + } + return status; +} + +int InitCardAndDownloadFirmware(struct bcm_mini_adapter *ps_adapter) +{ + int status; + unsigned int value = 0; + /* + * Create the threads first and then download the + * Firm/DDR Settings.. + */ + status = create_worker_threads(ps_adapter); + if (status < 0) + return status; + + status = bcm_parse_target_params(ps_adapter); + if (status) + return status; + + if (ps_adapter->chip_id >= T3LPB) { + rdmalt(ps_adapter, SYS_CFG, &value, sizeof(value)); + ps_adapter->syscfgBefFwDld = value; + + if ((value & 0x60) == 0) + ps_adapter->bFlashBoot = TRUE; + } + + reset_card_proc(ps_adapter); + + /* Initializing the NVM. */ + BcmInitNVM(ps_adapter); + status = ddr_init(ps_adapter); + if (status) { + pr_err(DRV_NAME "ddr_init Failed\n"); + return status; + } + + /* Download cfg file */ + status = buffDnldVerify(ps_adapter, + (PUCHAR)ps_adapter->pstargetparams, + sizeof(struct bcm_target_params), + CONFIG_BEGIN_ADDR); + if (status) { + BCM_DEBUG_PRINT(ps_adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Error downloading CFG file"); + goto OUT; + } + + if (register_networkdev(ps_adapter)) { + BCM_DEBUG_PRINT(ps_adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Register Netdevice failed. Cleanup needs to be performed."); + return -EIO; + } + + if (false == ps_adapter->AutoFirmDld) { + BCM_DEBUG_PRINT(ps_adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "AutoFirmDld Disabled in CFG File..\n"); + /* If Auto f/w download is disable, register the control interface, */ + /* register the control interface after the mailbox. */ + if (register_control_device_interface(ps_adapter) < 0) { + BCM_DEBUG_PRINT(ps_adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Register Control Device failed. Cleanup needs to be performed."); + return -EIO; + } + return STATUS_SUCCESS; + } + + /* + * Do the LED Settings here. It will be used by the Firmware Download + * Thread. + */ + + /* + * 1. If the LED Settings fails, do not stop and do the Firmware download. + * 2. This init would happened only if the cfg file is present, else + * call from the ioctl context. + */ + + status = InitLedSettings(ps_adapter); + if (status) { + BCM_DEBUG_PRINT(ps_adapter, DBG_TYPE_PRINTK, 0, 0, "INIT LED FAILED\n"); + return status; + } + + if (ps_adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { + ps_adapter->DriverState = DRIVER_INIT; + wake_up(&ps_adapter->LEDInfo.notify_led_event); + } + + if (ps_adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { + ps_adapter->DriverState = FW_DOWNLOAD; + wake_up(&ps_adapter->LEDInfo.notify_led_event); + } + + value = 0; + wrmalt(ps_adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 4, &value, sizeof(value)); + wrmalt(ps_adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 8, &value, sizeof(value)); + + if (ps_adapter->eNVMType == NVM_FLASH) { + status = PropagateCalParamsFromFlashToMemory(ps_adapter); + if (status) { + BCM_DEBUG_PRINT(ps_adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Propagation of Cal param failed .."); + goto OUT; + } + } + + /* Download Firmare */ + status = BcmFileDownload(ps_adapter, BIN_FILE, FIRMWARE_BEGIN_ADDR); + if (status != 0) { + BCM_DEBUG_PRINT(ps_adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "No Firmware File is present...\n"); + goto OUT; + } + + status = run_card_proc(ps_adapter); + if (status) { + BCM_DEBUG_PRINT(ps_adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "run_card_proc Failed\n"); + goto OUT; + } + + ps_adapter->fw_download_done = TRUE; + mdelay(10); + +OUT: + if (ps_adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { + ps_adapter->DriverState = FW_DOWNLOAD_DONE; + wake_up(&ps_adapter->LEDInfo.notify_led_event); + } + + return status; +} + +static int bcm_parse_target_params(struct bcm_mini_adapter *Adapter) +{ + struct file *flp = NULL; + char *buff; + int len = 0; + + buff = kmalloc(BUFFER_1K, GFP_KERNEL); + if (!buff) + return -ENOMEM; + + Adapter->pstargetparams = kmalloc(sizeof(struct bcm_target_params), GFP_KERNEL); + if (Adapter->pstargetparams == NULL) { + kfree(buff); + return -ENOMEM; + } + + flp = open_firmware_file(Adapter, CFG_FILE); + if (!flp) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "NOT ABLE TO OPEN THE %s FILE\n", CFG_FILE); + kfree(buff); + kfree(Adapter->pstargetparams); + Adapter->pstargetparams = NULL; + return -ENOENT; + } + len = kernel_read(flp, 0, buff, BUFFER_1K); + filp_close(flp, NULL); + + if (len != sizeof(struct bcm_target_params)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Mismatch in Target Param Structure!\n"); + kfree(buff); + kfree(Adapter->pstargetparams); + Adapter->pstargetparams = NULL; + return -ENOENT; + } + + /* Check for autolink in config params */ + /* + * Values in Adapter->pstargetparams are in network byte order + */ + memcpy(Adapter->pstargetparams, buff, sizeof(struct bcm_target_params)); + kfree(buff); + beceem_parse_target_struct(Adapter); + return STATUS_SUCCESS; +} + +void beceem_parse_target_struct(struct bcm_mini_adapter *Adapter) +{ + unsigned int uiHostDrvrCfg6 = 0, uiEEPROMFlag = 0; + + if (ntohl(Adapter->pstargetparams->m_u32PhyParameter2) & AUTO_SYNC_DISABLE) { + pr_info(DRV_NAME ": AutoSyncup is Disabled\n"); + Adapter->AutoSyncup = false; + } else { + pr_info(DRV_NAME ": AutoSyncup is Enabled\n"); + Adapter->AutoSyncup = TRUE; + } + + if (ntohl(Adapter->pstargetparams->HostDrvrConfig6) & AUTO_LINKUP_ENABLE) { + pr_info(DRV_NAME ": Enabling autolink up"); + Adapter->AutoLinkUp = TRUE; + } else { + pr_info(DRV_NAME ": Disabling autolink up"); + Adapter->AutoLinkUp = false; + } + /* Setting the DDR Setting.. */ + Adapter->DDRSetting = (ntohl(Adapter->pstargetparams->HostDrvrConfig6) >> 8)&0x0F; + Adapter->ulPowerSaveMode = (ntohl(Adapter->pstargetparams->HostDrvrConfig6)>>12)&0x0F; + pr_info(DRV_NAME ": DDR Setting: %x\n", Adapter->DDRSetting); + pr_info(DRV_NAME ": Power Save Mode: %lx\n", Adapter->ulPowerSaveMode); + if (ntohl(Adapter->pstargetparams->HostDrvrConfig6) & AUTO_FIRM_DOWNLOAD) { + pr_info(DRV_NAME ": Enabling Auto Firmware Download\n"); + Adapter->AutoFirmDld = TRUE; + } else { + pr_info(DRV_NAME ": Disabling Auto Firmware Download\n"); + Adapter->AutoFirmDld = false; + } + uiHostDrvrCfg6 = ntohl(Adapter->pstargetparams->HostDrvrConfig6); + Adapter->bMipsConfig = (uiHostDrvrCfg6>>20)&0x01; + pr_info(DRV_NAME ": MIPSConfig : 0x%X\n", Adapter->bMipsConfig); + /* used for backward compatibility. */ + Adapter->bDPLLConfig = (uiHostDrvrCfg6>>19)&0x01; + Adapter->PmuMode = (uiHostDrvrCfg6 >> 24) & 0x03; + pr_info(DRV_NAME ": PMU MODE: %x", Adapter->PmuMode); + + if ((uiHostDrvrCfg6 >> HOST_BUS_SUSPEND_BIT) & (0x01)) { + Adapter->bDoSuspend = TRUE; + pr_info(DRV_NAME ": Making DoSuspend TRUE as per configFile"); + } + + uiEEPROMFlag = ntohl(Adapter->pstargetparams->m_u32EEPROMFlag); + pr_info(DRV_NAME ": uiEEPROMFlag : 0x%X\n", uiEEPROMFlag); + Adapter->eNVMType = (enum bcm_nvm_type)((uiEEPROMFlag>>4)&0x3); + Adapter->bStatusWrite = (uiEEPROMFlag>>6)&0x1; + Adapter->uiSectorSizeInCFG = 1024*(0xFFFF & ntohl(Adapter->pstargetparams->HostDrvrConfig4)); + Adapter->bSectorSizeOverride = (bool) ((ntohl(Adapter->pstargetparams->HostDrvrConfig4))>>16)&0x1; + + if (ntohl(Adapter->pstargetparams->m_u32PowerSavingModeOptions) & 0x01) + Adapter->ulPowerSaveMode = DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE; + + if (Adapter->ulPowerSaveMode != DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) + doPowerAutoCorrection(Adapter); +} + +static void doPowerAutoCorrection(struct bcm_mini_adapter *psAdapter) +{ + unsigned int reporting_mode; + + reporting_mode = ntohl(psAdapter->pstargetparams->m_u32PowerSavingModeOptions) & 0x02; + psAdapter->bIsAutoCorrectEnabled = !((char)(psAdapter->ulPowerSaveMode >> 3) & 0x1); + + if (reporting_mode == TRUE) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "can't do suspen/resume as reporting mode is enable"); + psAdapter->bDoSuspend = false; + } + + if (psAdapter->bIsAutoCorrectEnabled && (psAdapter->chip_id >= T3LPB)) { + /* If reporting mode is enable, switch PMU to PMC */ + { + psAdapter->ulPowerSaveMode = DEVICE_POWERSAVE_MODE_AS_PMU_CLOCK_GATING; + psAdapter->bDoSuspend = false; + } + + /* clearing space bit[15..12] */ + psAdapter->pstargetparams->HostDrvrConfig6 &= ~(htonl((0xF << 12))); + /* placing the power save mode option */ + psAdapter->pstargetparams->HostDrvrConfig6 |= htonl((psAdapter->ulPowerSaveMode << 12)); + } else if (psAdapter->bIsAutoCorrectEnabled == false) { + /* remove the autocorrect disable bit set before dumping. */ + psAdapter->ulPowerSaveMode &= ~(1 << 3); + psAdapter->pstargetparams->HostDrvrConfig6 &= ~(htonl(1 << 15)); + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, MP_INIT, DBG_LVL_ALL, "Using Forced User Choice: %lx\n", psAdapter->ulPowerSaveMode); + } +} + +static void convertEndian(unsigned char rwFlag, unsigned int *puiBuffer, unsigned int uiByteCount) +{ + unsigned int uiIndex = 0; + + if (RWM_WRITE == rwFlag) { + for (uiIndex = 0; uiIndex < (uiByteCount/sizeof(unsigned int)); uiIndex++) + puiBuffer[uiIndex] = htonl(puiBuffer[uiIndex]); + } else { + for (uiIndex = 0; uiIndex < (uiByteCount/sizeof(unsigned int)); uiIndex++) + puiBuffer[uiIndex] = ntohl(puiBuffer[uiIndex]); + } +} + +int rdm(struct bcm_mini_adapter *Adapter, unsigned int uiAddress, PCHAR pucBuff, size_t sSize) +{ + return Adapter->interface_rdm(Adapter->pvInterfaceAdapter, + uiAddress, pucBuff, sSize); +} + +int wrm(struct bcm_mini_adapter *Adapter, unsigned int uiAddress, PCHAR pucBuff, size_t sSize) +{ + int iRetVal; + + iRetVal = Adapter->interface_wrm(Adapter->pvInterfaceAdapter, + uiAddress, pucBuff, sSize); + return iRetVal; +} + +int wrmalt(struct bcm_mini_adapter *Adapter, unsigned int uiAddress, unsigned int *pucBuff, size_t size) +{ + convertEndian(RWM_WRITE, pucBuff, size); + return wrm(Adapter, uiAddress, (PUCHAR)pucBuff, size); +} + +int rdmalt(struct bcm_mini_adapter *Adapter, unsigned int uiAddress, unsigned int *pucBuff, size_t size) +{ + int uiRetVal = 0; + + uiRetVal = rdm(Adapter, uiAddress, (PUCHAR)pucBuff, size); + convertEndian(RWM_READ, (unsigned int *)pucBuff, size); + + return uiRetVal; +} + +int wrmWithLock(struct bcm_mini_adapter *Adapter, unsigned int uiAddress, PCHAR pucBuff, size_t sSize) +{ + int status = STATUS_SUCCESS; + down(&Adapter->rdmwrmsync); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + status = -EACCES; + goto exit; + } + + status = wrm(Adapter, uiAddress, pucBuff, sSize); +exit: + up(&Adapter->rdmwrmsync); + return status; +} + +int wrmaltWithLock(struct bcm_mini_adapter *Adapter, unsigned int uiAddress, unsigned int *pucBuff, size_t size) +{ + int iRetVal = STATUS_SUCCESS; + + down(&Adapter->rdmwrmsync); + + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + iRetVal = -EACCES; + goto exit; + } + + iRetVal = wrmalt(Adapter, uiAddress, pucBuff, size); +exit: + up(&Adapter->rdmwrmsync); + return iRetVal; +} + +int rdmaltWithLock(struct bcm_mini_adapter *Adapter, unsigned int uiAddress, unsigned int *pucBuff, size_t size) +{ + int uiRetVal = STATUS_SUCCESS; + + down(&Adapter->rdmwrmsync); + if ((Adapter->IdleMode == TRUE) || + (Adapter->bShutStatus == TRUE) || + (Adapter->bPreparingForLowPowerMode == TRUE)) { + + uiRetVal = -EACCES; + goto exit; + } + + uiRetVal = rdmalt(Adapter, uiAddress, pucBuff, size); +exit: + up(&Adapter->rdmwrmsync); + return uiRetVal; +} + +static void HandleShutDownModeWakeup(struct bcm_mini_adapter *Adapter) +{ + int clear_abort_pattern = 0, Status = 0; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL, "====>\n"); + /* target has woken up From Shut Down */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL, "Clearing Shut Down Software abort pattern\n"); + Status = wrmalt(Adapter, SW_ABORT_IDLEMODE_LOC, (unsigned int *)&clear_abort_pattern, sizeof(clear_abort_pattern)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL, "WRM to SW_ABORT_IDLEMODE_LOC failed with err:%d", Status); + return; + } + + if (Adapter->ulPowerSaveMode != DEVICE_POWERSAVE_MODE_AS_PROTOCOL_IDLE_MODE) { + msleep(100); + InterfaceHandleShutdownModeWakeup(Adapter); + msleep(100); + } + + if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { + Adapter->DriverState = NO_NETWORK_ENTRY; + wake_up(&Adapter->LEDInfo.notify_led_event); + } + + Adapter->bTriedToWakeUpFromlowPowerMode = false; + Adapter->bShutStatus = false; + wake_up(&Adapter->lowpower_mode_wait_queue); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL, "<====\n"); +} + +static void SendShutModeResponse(struct bcm_mini_adapter *Adapter) +{ + struct bcm_link_request stShutdownResponse; + unsigned int NVMAccess = 0, lowPwrAbortMsg = 0; + unsigned int Status = 0; + + memset(&stShutdownResponse, 0, sizeof(struct bcm_link_request)); + stShutdownResponse.Leader.Status = LINK_UP_CONTROL_REQ; + stShutdownResponse.Leader.PLength = 8; /* 8 bytes; */ + stShutdownResponse.szData[0] = LINK_UP_ACK; + stShutdownResponse.szData[1] = LINK_SHUTDOWN_REQ_FROM_FIRMWARE; + + /********************************* + * down_trylock - + * if [ semaphore is available ] + * acquire semaphone and return value 0 ; + * else + * return non-zero value ; + * + ***********************************/ + + NVMAccess = down_trylock(&Adapter->NVMRdmWrmLock); + lowPwrAbortMsg = down_trylock(&Adapter->LowPowerModeSync); + + if (NVMAccess || lowPwrAbortMsg || atomic_read(&Adapter->TotalPacketCount)) { + if (!NVMAccess) + up(&Adapter->NVMRdmWrmLock); + + if (!lowPwrAbortMsg) + up(&Adapter->LowPowerModeSync); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL, "Device Access is going on NACK the Shut Down MODE\n"); + stShutdownResponse.szData[2] = SHUTDOWN_NACK_FROM_DRIVER; /* NACK- device access is going on. */ + Adapter->bPreparingForLowPowerMode = false; + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL, "Sending SHUTDOWN MODE ACK\n"); + stShutdownResponse.szData[2] = SHUTDOWN_ACK_FROM_DRIVER; /* ShutDown ACK */ + + /* Wait for the LED to TURN OFF before sending ACK response */ + if (Adapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) { + int iRetVal = 0; + + /* Wake the LED Thread with LOWPOWER_MODE_ENTER State */ + Adapter->DriverState = LOWPOWER_MODE_ENTER; + wake_up(&Adapter->LEDInfo.notify_led_event); + + /* Wait for 1 SEC for LED to OFF */ + iRetVal = wait_event_timeout(Adapter->LEDInfo.idleModeSyncEvent, Adapter->LEDInfo.bIdle_led_off, msecs_to_jiffies(1000)); + + /* If Timed Out to Sync IDLE MODE Enter, do IDLE mode Exit and Send NACK to device */ + if (iRetVal <= 0) { + stShutdownResponse.szData[1] = SHUTDOWN_NACK_FROM_DRIVER; /* NACK- device access is going on. */ + Adapter->DriverState = NO_NETWORK_ENTRY; + wake_up(&Adapter->LEDInfo.notify_led_event); + } + } + + if (stShutdownResponse.szData[2] == SHUTDOWN_ACK_FROM_DRIVER) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL, "ACKING SHUTDOWN MODE !!!!!!!!!"); + down(&Adapter->rdmwrmsync); + Adapter->bPreparingForLowPowerMode = TRUE; + up(&Adapter->rdmwrmsync); + /* Killing all URBS. */ + if (Adapter->bDoSuspend == TRUE) + Bcm_kill_all_URBs((struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter)); + } else { + Adapter->bPreparingForLowPowerMode = false; + } + + if (!NVMAccess) + up(&Adapter->NVMRdmWrmLock); + + if (!lowPwrAbortMsg) + up(&Adapter->LowPowerModeSync); + } + + Status = CopyBufferToControlPacket(Adapter, &stShutdownResponse); + if ((Status != STATUS_SUCCESS)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL, "fail to send the Idle mode Request\n"); + Adapter->bPreparingForLowPowerMode = false; + StartInterruptUrb((struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter)); + } +} + +static void HandleShutDownModeRequest(struct bcm_mini_adapter *Adapter, PUCHAR pucBuffer) +{ + unsigned int uiResetValue = 0; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL, "====>\n"); + + if (*(pucBuffer+1) == COMPLETE_WAKE_UP_NOTIFICATION_FRM_FW) { + HandleShutDownModeWakeup(Adapter); + } else if (*(pucBuffer+1) == LINK_SHUTDOWN_REQ_FROM_FIRMWARE) { + /* Target wants to go to Shut Down Mode */ + /* InterfacePrepareForShutdown(Adapter); */ + if (Adapter->chip_id == BCS220_2 || + Adapter->chip_id == BCS220_2BC || + Adapter->chip_id == BCS250_BC || + Adapter->chip_id == BCS220_3) { + + rdmalt(Adapter, HPM_CONFIG_MSW, &uiResetValue, 4); + uiResetValue |= (1<<17); + wrmalt(Adapter, HPM_CONFIG_MSW, &uiResetValue, 4); + } + + SendShutModeResponse(Adapter); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL, "ShutDownModeResponse:Notification received: Sending the response(Ack/Nack)\n"); + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, MP_SHUTDOWN, DBG_LVL_ALL, "<====\n"); + return; +} + +void ResetCounters(struct bcm_mini_adapter *Adapter) +{ + beceem_protocol_reset(Adapter); + Adapter->CurrNumRecvDescs = 0; + Adapter->PrevNumRecvDescs = 0; + Adapter->LinkUpStatus = 0; + Adapter->LinkStatus = 0; + atomic_set(&Adapter->cntrlpktCnt, 0); + atomic_set(&Adapter->TotalPacketCount, 0); + Adapter->fw_download_done = false; + Adapter->LinkStatus = 0; + Adapter->AutoLinkUp = false; + Adapter->IdleMode = false; + Adapter->bShutStatus = false; +} + +struct bcm_classifier_rule *GetFragIPClsEntry(struct bcm_mini_adapter *Adapter, USHORT usIpIdentification, ULONG SrcIP) +{ + unsigned int uiIndex = 0; + for (uiIndex = 0; uiIndex < MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES; uiIndex++) { + if ((Adapter->astFragmentedPktClassifierTable[uiIndex].bUsed) && + (Adapter->astFragmentedPktClassifierTable[uiIndex].usIpIdentification == usIpIdentification) && + (Adapter->astFragmentedPktClassifierTable[uiIndex].ulSrcIpAddress == SrcIP) && + !Adapter->astFragmentedPktClassifierTable[uiIndex].bOutOfOrderFragment) + + return Adapter->astFragmentedPktClassifierTable[uiIndex].pstMatchedClassifierEntry; + } + return NULL; +} + +void AddFragIPClsEntry(struct bcm_mini_adapter *Adapter, struct bcm_fragmented_packet_info *psFragPktInfo) +{ + unsigned int uiIndex = 0; + for (uiIndex = 0; uiIndex < MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES; uiIndex++) { + if (!Adapter->astFragmentedPktClassifierTable[uiIndex].bUsed) { + memcpy(&Adapter->astFragmentedPktClassifierTable[uiIndex], psFragPktInfo, sizeof(struct bcm_fragmented_packet_info)); + break; + } + } +} + +void DelFragIPClsEntry(struct bcm_mini_adapter *Adapter, USHORT usIpIdentification, ULONG SrcIp) +{ + unsigned int uiIndex = 0; + for (uiIndex = 0; uiIndex < MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES; uiIndex++) { + if ((Adapter->astFragmentedPktClassifierTable[uiIndex].bUsed) && + (Adapter->astFragmentedPktClassifierTable[uiIndex].usIpIdentification == usIpIdentification) && + (Adapter->astFragmentedPktClassifierTable[uiIndex].ulSrcIpAddress == SrcIp)) + + memset(&Adapter->astFragmentedPktClassifierTable[uiIndex], 0, sizeof(struct bcm_fragmented_packet_info)); + } +} + +void update_per_cid_rx(struct bcm_mini_adapter *Adapter) +{ + unsigned int qindex = 0; + + if ((jiffies - Adapter->liDrainCalculated) < XSECONDS) + return; + + for (qindex = 0; qindex < HiPriority; qindex++) { + if (Adapter->PackInfo[qindex].ucDirection == 0) { + Adapter->PackInfo[qindex].uiCurrentRxRate = + (Adapter->PackInfo[qindex].uiCurrentRxRate + + Adapter->PackInfo[qindex].uiThisPeriodRxBytes) / 2; + + Adapter->PackInfo[qindex].uiThisPeriodRxBytes = 0; + } else { + Adapter->PackInfo[qindex].uiCurrentDrainRate = + (Adapter->PackInfo[qindex].uiCurrentDrainRate + + Adapter->PackInfo[qindex].uiThisPeriodSentBytes) / 2; + Adapter->PackInfo[qindex].uiThisPeriodSentBytes = 0; + } + } + Adapter->liDrainCalculated = jiffies; +} + +void update_per_sf_desc_cnts(struct bcm_mini_adapter *Adapter) +{ + int iIndex = 0; + u32 uibuff[MAX_TARGET_DSX_BUFFERS]; + int bytes; + + if (!atomic_read(&Adapter->uiMBupdate)) + return; + + bytes = rdmaltWithLock(Adapter, TARGET_SFID_TXDESC_MAP_LOC, (unsigned int *)uibuff, sizeof(unsigned int) * MAX_TARGET_DSX_BUFFERS); + if (bytes < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "rdm failed\n"); + return; + } + + for (iIndex = 0; iIndex < HiPriority; iIndex++) { + if (Adapter->PackInfo[iIndex].bValid && Adapter->PackInfo[iIndex].ucDirection) { + if (Adapter->PackInfo[iIndex].usVCID_Value < MAX_TARGET_DSX_BUFFERS) + atomic_set(&Adapter->PackInfo[iIndex].uiPerSFTxResourceCount, uibuff[Adapter->PackInfo[iIndex].usVCID_Value]); + else + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Invalid VCID : %x\n", Adapter->PackInfo[iIndex].usVCID_Value); + } + } + atomic_set(&Adapter->uiMBupdate, false); +} + +void flush_queue(struct bcm_mini_adapter *Adapter, unsigned int iQIndex) +{ + struct sk_buff *PacketToDrop = NULL; + struct net_device_stats *netstats = &Adapter->dev->stats; + spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock); + + while (Adapter->PackInfo[iQIndex].FirstTxQueue && atomic_read(&Adapter->TotalPacketCount)) { + PacketToDrop = Adapter->PackInfo[iQIndex].FirstTxQueue; + if (PacketToDrop && PacketToDrop->len) { + netstats->tx_dropped++; + DEQUEUEPACKET(Adapter->PackInfo[iQIndex].FirstTxQueue, Adapter->PackInfo[iQIndex].LastTxQueue); + Adapter->PackInfo[iQIndex].uiCurrentPacketsOnHost--; + Adapter->PackInfo[iQIndex].uiCurrentBytesOnHost -= PacketToDrop->len; + + /* Adding dropped statistics */ + Adapter->PackInfo[iQIndex].uiDroppedCountBytes += PacketToDrop->len; + Adapter->PackInfo[iQIndex].uiDroppedCountPackets++; + dev_kfree_skb(PacketToDrop); + atomic_dec(&Adapter->TotalPacketCount); + } + } + spin_unlock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock); +} + +static void beceem_protocol_reset(struct bcm_mini_adapter *Adapter) +{ + int i; + if (netif_msg_link(Adapter)) + pr_notice(PFX "%s: protocol reset\n", Adapter->dev->name); + + netif_carrier_off(Adapter->dev); + netif_stop_queue(Adapter->dev); + + Adapter->IdleMode = false; + Adapter->LinkUpStatus = false; + ClearTargetDSXBuffer(Adapter, 0, TRUE); + /* Delete All Classifier Rules */ + + for (i = 0; i < HiPriority; i++) + DeleteAllClassifiersForSF(Adapter, i); + + flush_all_queues(Adapter); + + if (Adapter->TimerActive == TRUE) + Adapter->TimerActive = false; + + memset(Adapter->astFragmentedPktClassifierTable, 0, sizeof(struct bcm_fragmented_packet_info) * MAX_FRAGMENTEDIP_CLASSIFICATION_ENTRIES); + + for (i = 0; i < HiPriority; i++) { + /* resetting only the first size (S_MIBS_SERVICEFLOW_TABLE) for the SF. */ + /* It is same between MIBs and SF. */ + memset(&Adapter->PackInfo[i].stMibsExtServiceFlowTable, 0, sizeof(struct bcm_mibs_parameters)); + } +} diff --git a/drivers/staging/bcm/PHSDefines.h b/drivers/staging/bcm/PHSDefines.h new file mode 100644 index 00000000000..cd78ee4ffa2 --- /dev/null +++ b/drivers/staging/bcm/PHSDefines.h @@ -0,0 +1,94 @@ +#ifndef BCM_PHS_DEFINES_H +#define BCM_PHS_DEFINES_H + +#define PHS_INVALID_TABLE_INDEX 0xffffffff +#define PHS_MEM_TAG "_SHP" + +/* PHS Defines */ +#define STATUS_PHS_COMPRESSED 0xa1 +#define STATUS_PHS_NOCOMPRESSION 0xa2 +#define APPLY_PHS 1 +#define MAX_NO_BIT 7 +#define ZERO_PHSI 0 +#define VERIFY 0 +#define SIZE_MULTIPLE_32 4 +#define UNCOMPRESSED_PACKET 0 +#define DYNAMIC 0 +#define SUPPRESS 0x80 +#define NO_CLASSIFIER_MATCH 0 +#define SEND_PACKET_UNCOMPRESSED 0 +#define PHSI_IS_ZERO 0 +#define PHSI_LEN 1 +#define ERROR_LEN 0 +#define PHS_BUFFER_SIZE 1532 +#define MAX_PHSRULE_PER_SF 20 +#define MAX_SERVICEFLOWS 17 + +/* PHS Error Defines */ +#define PHS_SUCCESS 0 +#define ERR_PHS_INVALID_DEVICE_EXETENSION 0x800 +#define ERR_PHS_INVALID_PHS_RULE 0x801 +#define ERR_PHS_RULE_ALREADY_EXISTS 0x802 +#define ERR_SF_MATCH_FAIL 0x803 +#define ERR_INVALID_CLASSIFIERTABLE_FOR_SF 0x804 +#define ERR_SFTABLE_FULL 0x805 +#define ERR_CLSASSIFIER_TABLE_FULL 0x806 +#define ERR_PHSRULE_MEMALLOC_FAIL 0x807 +#define ERR_CLSID_MATCH_FAIL 0x808 +#define ERR_PHSRULE_MATCH_FAIL 0x809 + +struct bcm_phs_rule { + u8 u8PHSI; + u8 u8PHSFLength; + u8 u8PHSF[MAX_PHS_LENGTHS]; + u8 u8PHSMLength; + u8 u8PHSM[MAX_PHS_LENGTHS]; + u8 u8PHSS; + u8 u8PHSV; + u8 u8RefCnt; + u8 bUnclassifiedPHSRule; + u8 u8Reserved[3]; + long PHSModifiedBytes; + unsigned long PHSModifiedNumPackets; + unsigned long PHSErrorNumPackets; +}; + +enum bcm_phs_classifier_context { + eActiveClassifierRuleContext, + eOldClassifierRuleContext +}; + +struct bcm_phs_classifier_entry { + u8 bUsed; + u16 uiClassifierRuleId; + u8 u8PHSI; + struct bcm_phs_rule *pstPhsRule; + u8 bUnclassifiedPHSRule; +}; + +struct bcm_phs_classifier_table { + u16 uiTotalClassifiers; + struct bcm_phs_classifier_entry stActivePhsRulesList[MAX_PHSRULE_PER_SF]; + struct bcm_phs_classifier_entry stOldPhsRulesList[MAX_PHSRULE_PER_SF]; + u16 uiOldestPhsRuleIndex; +}; + +struct bcm_phs_entry { + u8 bUsed; + u16 uiVcid; + struct bcm_phs_classifier_table *pstClassifierTable; +}; + +struct bcm_phs_table { + u16 uiTotalServiceFlows; + struct bcm_phs_entry stSFList[MAX_SERVICEFLOWS]; +}; + +struct bcm_phs_extension { + /* PHS Specific data */ + struct bcm_phs_table *pstServiceFlowPhsRulesTable; + void *CompressedTxBuffer; + void *UnCompressedRxBuffer; +}; + +#endif diff --git a/drivers/staging/bcm/PHSModule.c b/drivers/staging/bcm/PHSModule.c new file mode 100644 index 00000000000..07c5a0bae1e --- /dev/null +++ b/drivers/staging/bcm/PHSModule.c @@ -0,0 +1,1448 @@ +#include "headers.h" + +static UINT CreateSFToClassifierRuleMapping(B_UINT16 uiVcid, B_UINT16 uiClsId, struct bcm_phs_table *psServiceFlowTable, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI); + +static UINT CreateClassiferToPHSRuleMapping(B_UINT16 uiVcid, B_UINT16 uiClsId, struct bcm_phs_entry *pstServiceFlowEntry, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI); + +static UINT CreateClassifierPHSRule(B_UINT16 uiClsId, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *psPhsRule, enum bcm_phs_classifier_context eClsContext, B_UINT8 u8AssociatedPHSI); + +static UINT UpdateClassifierPHSRule(B_UINT16 uiClsId, struct bcm_phs_classifier_entry *pstClassifierEntry, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *psPhsRule, B_UINT8 u8AssociatedPHSI); + +static bool ValidatePHSRuleComplete(struct bcm_phs_rule *psPhsRule); + +static bool DerefPhsRule(B_UINT16 uiClsId, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *pstPhsRule); + +static UINT GetClassifierEntry(struct bcm_phs_classifier_table *pstClassifierTable, B_UINT32 uiClsid, enum bcm_phs_classifier_context eClsContext, struct bcm_phs_classifier_entry **ppstClassifierEntry); + +static UINT GetPhsRuleEntry(struct bcm_phs_classifier_table *pstClassifierTable, B_UINT32 uiPHSI, enum bcm_phs_classifier_context eClsContext, struct bcm_phs_rule **ppstPhsRule); + +static void free_phs_serviceflow_rules(struct bcm_phs_table *psServiceFlowRulesTable); + +static int phs_compress(struct bcm_phs_rule *phs_members, unsigned char *in_buf, + unsigned char *out_buf, unsigned int *header_size, UINT *new_header_size); + +static int verify_suppress_phsf(unsigned char *in_buffer, unsigned char *out_buffer, + unsigned char *phsf, unsigned char *phsm, unsigned int phss, unsigned int phsv, UINT *new_header_size); + +static int phs_decompress(unsigned char *in_buf, unsigned char *out_buf, + struct bcm_phs_rule *phs_rules, UINT *header_size); + +static ULONG PhsCompress(void *pvContext, + B_UINT16 uiVcid, + B_UINT16 uiClsId, + void *pvInputBuffer, + void *pvOutputBuffer, + UINT *pOldHeaderSize, + UINT *pNewHeaderSize); + +static ULONG PhsDeCompress(void *pvContext, + B_UINT16 uiVcid, + void *pvInputBuffer, + void *pvOutputBuffer, + UINT *pInHeaderSize, + UINT *pOutHeaderSize); + +#define IN +#define OUT + +/* + * Function: PHSTransmit + * Description: This routine handle PHS(Payload Header Suppression for Tx path. + * It extracts a fragment of the NDIS_PACKET containing the header + * to be suppressed. It then suppresses the header by invoking PHS exported compress routine. + * The header data after suppression is copied back to the NDIS_PACKET. + * + * Input parameters: IN struct bcm_mini_adapter *Adapter - Miniport Adapter Context + * IN Packet - NDIS packet containing data to be transmitted + * IN USHORT Vcid - vcid pertaining to connection on which the packet is being sent.Used to + * identify PHS rule to be applied. + * B_UINT16 uiClassifierRuleID - Classifier Rule ID + * BOOLEAN bHeaderSuppressionEnabled - indicates if header suprression is enabled for SF. + * + * Return: STATUS_SUCCESS - If the send was successful. + * Other - If an error occurred. + */ + +int PHSTransmit(struct bcm_mini_adapter *Adapter, + struct sk_buff **pPacket, + USHORT Vcid, + B_UINT16 uiClassifierRuleID, + bool bHeaderSuppressionEnabled, + UINT *PacketLen, + UCHAR bEthCSSupport) +{ + /* PHS Sepcific */ + UINT unPHSPktHdrBytesCopied = 0; + UINT unPhsOldHdrSize = 0; + UINT unPHSNewPktHeaderLen = 0; + /* Pointer to PHS IN Hdr Buffer */ + PUCHAR pucPHSPktHdrInBuf = Adapter->stPhsTxContextInfo.ucaHdrSuppressionInBuf; + /* Pointer to PHS OUT Hdr Buffer */ + PUCHAR pucPHSPktHdrOutBuf = Adapter->stPhsTxContextInfo.ucaHdrSuppressionOutBuf; + UINT usPacketType; + UINT BytesToRemove = 0; + bool bPHSI = 0; + LONG ulPhsStatus = 0; + UINT numBytesCompressed = 0; + struct sk_buff *newPacket = NULL; + struct sk_buff *Packet = *pPacket; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "In PHSTransmit"); + + if (!bEthCSSupport) + BytesToRemove = ETH_HLEN; + /* + * Accumulate the header upto the size we support suppression + * from NDIS packet + */ + + usPacketType = ((struct ethhdr *)(Packet->data))->h_proto; + + pucPHSPktHdrInBuf = Packet->data + BytesToRemove; + /* considering data after ethernet header */ + if ((*PacketLen - BytesToRemove) < MAX_PHS_LENGTHS) + unPHSPktHdrBytesCopied = (*PacketLen - BytesToRemove); + else + unPHSPktHdrBytesCopied = MAX_PHS_LENGTHS; + + if ((unPHSPktHdrBytesCopied > 0) && + (unPHSPktHdrBytesCopied <= MAX_PHS_LENGTHS)) { + + /* + * Step 2 Suppress Header using PHS and fill into intermediate ucaPHSPktHdrOutBuf. + * Suppress only if IP Header and PHS Enabled For the Service Flow + */ + if (((usPacketType == ETHERNET_FRAMETYPE_IPV4) || + (usPacketType == ETHERNET_FRAMETYPE_IPV6)) && + (bHeaderSuppressionEnabled)) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nTrying to PHS Compress Using Classifier rule 0x%X", uiClassifierRuleID); + unPHSNewPktHeaderLen = unPHSPktHdrBytesCopied; + ulPhsStatus = PhsCompress(&Adapter->stBCMPhsContext, + Vcid, + uiClassifierRuleID, + pucPHSPktHdrInBuf, + pucPHSPktHdrOutBuf, + &unPhsOldHdrSize, + &unPHSNewPktHeaderLen); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nPHS Old header Size : %d New Header Size %d\n", unPhsOldHdrSize, unPHSNewPktHeaderLen); + + if (unPHSNewPktHeaderLen == unPhsOldHdrSize) { + + if (ulPhsStatus == STATUS_PHS_COMPRESSED) + bPHSI = *pucPHSPktHdrOutBuf; + + ulPhsStatus = STATUS_PHS_NOCOMPRESSION; + } + + if (ulPhsStatus == STATUS_PHS_COMPRESSED) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "PHS Sending packet Compressed"); + + if (skb_cloned(Packet)) { + newPacket = skb_copy(Packet, GFP_ATOMIC); + + if (newPacket == NULL) + return STATUS_FAILURE; + + dev_kfree_skb(Packet); + *pPacket = Packet = newPacket; + pucPHSPktHdrInBuf = Packet->data + BytesToRemove; + } + + numBytesCompressed = unPhsOldHdrSize - (unPHSNewPktHeaderLen + PHSI_LEN); + + memcpy(pucPHSPktHdrInBuf + numBytesCompressed, pucPHSPktHdrOutBuf, unPHSNewPktHeaderLen + PHSI_LEN); + memcpy(Packet->data + numBytesCompressed, Packet->data, BytesToRemove); + skb_pull(Packet, numBytesCompressed); + + return STATUS_SUCCESS; + } else { + /* if one byte headroom is not available, increase it through skb_cow */ + if (!(skb_headroom(Packet) > 0)) { + + if (skb_cow(Packet, 1)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "SKB Cow Failed\n"); + return STATUS_FAILURE; + } + } + skb_push(Packet, 1); + + /* + * CAUTION: The MAC Header is getting corrupted + * here for IP CS - can be saved by copying 14 + * Bytes. not needed .... hence corrupting it. + */ + *(Packet->data + BytesToRemove) = bPHSI; + return STATUS_SUCCESS; + } + } else { + + if (!bHeaderSuppressionEnabled) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nHeader Suppression Disabled For SF: No PHS\n"); + + return STATUS_SUCCESS; + } + } + + /* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL,"PHSTransmit : Dumping data packet After PHS"); */ + return STATUS_SUCCESS; +} + +int PHSReceive(struct bcm_mini_adapter *Adapter, + USHORT usVcid, + struct sk_buff *packet, + UINT *punPacketLen, + UCHAR *pucEthernetHdr, + UINT bHeaderSuppressionEnabled) +{ + u32 nStandardPktHdrLen = 0; + u32 nTotalsuppressedPktHdrBytes = 0; + int ulPhsStatus = 0; + PUCHAR pucInBuff = NULL; + UINT TotalBytesAdded = 0; + + if (!bHeaderSuppressionEnabled) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "\nPhs Disabled for incoming packet"); + return ulPhsStatus; + } + + pucInBuff = packet->data; + + /* Restore PHS suppressed header */ + nStandardPktHdrLen = packet->len; + ulPhsStatus = PhsDeCompress(&Adapter->stBCMPhsContext, + usVcid, + pucInBuff, + Adapter->ucaPHSPktRestoreBuf, + &nTotalsuppressedPktHdrBytes, + &nStandardPktHdrLen); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "\nSuppressed PktHdrLen : 0x%x Restored PktHdrLen : 0x%x", + nTotalsuppressedPktHdrBytes, nStandardPktHdrLen); + + if (ulPhsStatus != STATUS_PHS_COMPRESSED) { + skb_pull(packet, 1); + return STATUS_SUCCESS; + } else { + TotalBytesAdded = nStandardPktHdrLen - nTotalsuppressedPktHdrBytes - PHSI_LEN; + + if (TotalBytesAdded) { + if (skb_headroom(packet) >= (SKB_RESERVE_ETHERNET_HEADER + TotalBytesAdded)) + skb_push(packet, TotalBytesAdded); + else { + if (skb_cow(packet, skb_headroom(packet) + TotalBytesAdded)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "cow failed in receive\n"); + return STATUS_FAILURE; + } + + skb_push(packet, TotalBytesAdded); + } + } + + memcpy(packet->data, Adapter->ucaPHSPktRestoreBuf, nStandardPktHdrLen); + } + + return STATUS_SUCCESS; +} + +void DumpFullPacket(UCHAR *pBuf, UINT nPktLen) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dumping Data Packet"); + BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, pBuf, nPktLen); +} + +/* + * Procedure: phs_init + * + * Description: This routine is responsible for allocating memory for classifier and + * PHS rules. + * + * Arguments: + * pPhsdeviceExtension - ptr to Device extension containing PHS Classifier rules and PHS Rules , RX, TX buffer etc + * + * Returns: + * TRUE(1) -If allocation of memory was successful. + * FALSE -If allocation of memory fails. + */ +int phs_init(struct bcm_phs_extension *pPhsdeviceExtension, struct bcm_mini_adapter *Adapter) +{ + int i; + struct bcm_phs_table *pstServiceFlowTable; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nPHS:phs_init function"); + + if (pPhsdeviceExtension->pstServiceFlowPhsRulesTable) + return -EINVAL; + + pPhsdeviceExtension->pstServiceFlowPhsRulesTable = kzalloc(sizeof(struct bcm_phs_table), GFP_KERNEL); + + if (!pPhsdeviceExtension->pstServiceFlowPhsRulesTable) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation ServiceFlowPhsRulesTable failed"); + return -ENOMEM; + } + + pstServiceFlowTable = pPhsdeviceExtension->pstServiceFlowPhsRulesTable; + for (i = 0; i < MAX_SERVICEFLOWS; i++) { + struct bcm_phs_entry sServiceFlow = pstServiceFlowTable->stSFList[i]; + sServiceFlow.pstClassifierTable = kzalloc(sizeof(struct bcm_phs_classifier_table), GFP_KERNEL); + if (!sServiceFlow.pstClassifierTable) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed"); + free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable); + pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL; + return -ENOMEM; + } + } + + pPhsdeviceExtension->CompressedTxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL); + if (pPhsdeviceExtension->CompressedTxBuffer == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed"); + free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable); + pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL; + return -ENOMEM; + } + + pPhsdeviceExtension->UnCompressedRxBuffer = kmalloc(PHS_BUFFER_SIZE, GFP_KERNEL); + if (pPhsdeviceExtension->UnCompressedRxBuffer == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAllocation failed"); + kfree(pPhsdeviceExtension->CompressedTxBuffer); + free_phs_serviceflow_rules(pPhsdeviceExtension->pstServiceFlowPhsRulesTable); + pPhsdeviceExtension->pstServiceFlowPhsRulesTable = NULL; + return -ENOMEM; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n phs_init Successful"); + return STATUS_SUCCESS; +} + +int PhsCleanup(IN struct bcm_phs_extension *pPHSDeviceExt) +{ + if (pPHSDeviceExt->pstServiceFlowPhsRulesTable) { + free_phs_serviceflow_rules(pPHSDeviceExt->pstServiceFlowPhsRulesTable); + pPHSDeviceExt->pstServiceFlowPhsRulesTable = NULL; + } + + kfree(pPHSDeviceExt->CompressedTxBuffer); + pPHSDeviceExt->CompressedTxBuffer = NULL; + + kfree(pPHSDeviceExt->UnCompressedRxBuffer); + pPHSDeviceExt->UnCompressedRxBuffer = NULL; + + return 0; +} + +/* + * PHS functions + * PhsUpdateClassifierRule + * + * Routine Description: + * Exported function to add or modify a PHS Rule. + * + * Arguments: + * IN void* pvContext - PHS Driver Specific Context + * IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rule applies + * IN B_UINT16 uiClsId - The Classifier ID within the Service Flow for which the PHS rule applies. + * IN struct bcm_phs_rule *psPhsRule - The PHS Rule strcuture to be added to the PHS Rule table. + * + * Return Value: + * + * 0 if successful, + * >0 Error. + */ +ULONG PhsUpdateClassifierRule(IN void *pvContext, + IN B_UINT16 uiVcid , + IN B_UINT16 uiClsId , + IN struct bcm_phs_rule *psPhsRule, + IN B_UINT8 u8AssociatedPHSI) +{ + ULONG lStatus = 0; + UINT nSFIndex = 0; + struct bcm_phs_entry *pstServiceFlowEntry = NULL; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "PHS With Corr2 Changes\n"); + + if (pDeviceExtension == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "Invalid Device Extension\n"); + return ERR_PHS_INVALID_DEVICE_EXETENSION; + } + + if (u8AssociatedPHSI == 0) + return ERR_PHS_INVALID_PHS_RULE; + + /* Retrieve the SFID Entry Index for requested Service Flow */ + nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable, + uiVcid, &pstServiceFlowEntry); + + if (nSFIndex == PHS_INVALID_TABLE_INDEX) { + /* This is a new SF. Create a mapping entry for this */ + lStatus = CreateSFToClassifierRuleMapping(uiVcid, uiClsId, + pDeviceExtension->pstServiceFlowPhsRulesTable, psPhsRule, u8AssociatedPHSI); + return lStatus; + } + + /* SF already Exists Add PHS Rule to existing SF */ + lStatus = CreateClassiferToPHSRuleMapping(uiVcid, uiClsId, + pstServiceFlowEntry, psPhsRule, u8AssociatedPHSI); + + return lStatus; +} + +/* + * PhsDeletePHSRule + * + * Routine Description: + * Deletes the specified phs Rule within Vcid + * + * Arguments: + * IN void* pvContext - PHS Driver Specific Context + * IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rule applies + * IN B_UINT8 u8PHSI - the PHS Index identifying PHS rule to be deleted. + * + * Return Value: + * + * 0 if successful, + * >0 Error. + */ +ULONG PhsDeletePHSRule(IN void *pvContext, IN B_UINT16 uiVcid, IN B_UINT8 u8PHSI) +{ + UINT nSFIndex = 0, nClsidIndex = 0; + struct bcm_phs_entry *pstServiceFlowEntry = NULL; + struct bcm_phs_classifier_table *pstClassifierRulesTable = NULL; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "======>\n"); + + if (pDeviceExtension) { + /* Retrieve the SFID Entry Index for requested Service Flow */ + nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable, uiVcid, &pstServiceFlowEntry); + + if (nSFIndex == PHS_INVALID_TABLE_INDEX) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "SFID Match Failed\n"); + return ERR_SF_MATCH_FAIL; + } + + pstClassifierRulesTable = pstServiceFlowEntry->pstClassifierTable; + if (pstClassifierRulesTable) { + for (nClsidIndex = 0; nClsidIndex < MAX_PHSRULE_PER_SF; nClsidIndex++) { + if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].bUsed && pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule) { + if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8PHSI == u8PHSI) { + + if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt) + pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt--; + + if (0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt) + kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule); + + memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0, + sizeof(struct bcm_phs_classifier_entry)); + } + } + } + } + } + return 0; +} + +/* + * PhsDeleteClassifierRule + * + * Routine Description: + * Exported function to Delete a PHS Rule for the SFID,CLSID Pair. + * + * Arguments: + * IN void* pvContext - PHS Driver Specific Context + * IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rule applies + * IN B_UINT16 uiClsId - The Classifier ID within the Service Flow for which the PHS rule applies. + * + * Return Value: + * + * 0 if successful, + * >0 Error. + */ +ULONG PhsDeleteClassifierRule(IN void *pvContext, IN B_UINT16 uiVcid, IN B_UINT16 uiClsId) +{ + UINT nSFIndex = 0, nClsidIndex = 0; + struct bcm_phs_entry *pstServiceFlowEntry = NULL; + struct bcm_phs_classifier_entry *pstClassifierEntry = NULL; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext; + + if (pDeviceExtension) { + /* Retrieve the SFID Entry Index for requested Service Flow */ + nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable, uiVcid, &pstServiceFlowEntry); + if (nSFIndex == PHS_INVALID_TABLE_INDEX) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "SFID Match Failed\n"); + return ERR_SF_MATCH_FAIL; + } + + nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable, + uiClsId, eActiveClassifierRuleContext, &pstClassifierEntry); + + if ((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule)) { + if (pstClassifierEntry->pstPhsRule) { + if (pstClassifierEntry->pstPhsRule->u8RefCnt) + pstClassifierEntry->pstPhsRule->u8RefCnt--; + + if (0 == pstClassifierEntry->pstPhsRule->u8RefCnt) + kfree(pstClassifierEntry->pstPhsRule); + } + memset(pstClassifierEntry, 0, sizeof(struct bcm_phs_classifier_entry)); + } + + nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable, + uiClsId, eOldClassifierRuleContext, &pstClassifierEntry); + + if ((nClsidIndex != PHS_INVALID_TABLE_INDEX) && (!pstClassifierEntry->bUnclassifiedPHSRule)) { + kfree(pstClassifierEntry->pstPhsRule); + memset(pstClassifierEntry, 0, sizeof(struct bcm_phs_classifier_entry)); + } + } + return 0; +} + +/* + * PhsDeleteSFRules + * + * Routine Description: + * Exported function to Delete a all PHS Rules for the SFID. + * + * Arguments: + * IN void* pvContext - PHS Driver Specific Context + * IN B_UINT16 uiVcid - The Service Flow ID for which the PHS rules need to be deleted + * + * Return Value: + * + * 0 if successful, + * >0 Error. + */ +ULONG PhsDeleteSFRules(IN void *pvContext, IN B_UINT16 uiVcid) +{ + UINT nSFIndex = 0, nClsidIndex = 0; + struct bcm_phs_entry *pstServiceFlowEntry = NULL; + struct bcm_phs_classifier_table *pstClassifierRulesTable = NULL; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "====>\n"); + + if (pDeviceExtension) { + /* Retrieve the SFID Entry Index for requested Service Flow */ + nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable, + uiVcid, &pstServiceFlowEntry); + if (nSFIndex == PHS_INVALID_TABLE_INDEX) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "SFID Match Failed\n"); + return ERR_SF_MATCH_FAIL; + } + + pstClassifierRulesTable = pstServiceFlowEntry->pstClassifierTable; + if (pstClassifierRulesTable) { + for (nClsidIndex = 0; nClsidIndex < MAX_PHSRULE_PER_SF; nClsidIndex++) { + if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule) { + + if (pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt) + pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt--; + + if (0 == pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt) + kfree(pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule); + + pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex].pstPhsRule = NULL; + } + memset(&pstClassifierRulesTable->stActivePhsRulesList[nClsidIndex], 0, sizeof(struct bcm_phs_classifier_entry)); + if (pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule) { + + if (pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt) + pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt--; + + if (0 == pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule->u8RefCnt) + kfree(pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule); + + pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex].pstPhsRule = NULL; + } + memset(&pstClassifierRulesTable->stOldPhsRulesList[nClsidIndex], 0, sizeof(struct bcm_phs_classifier_entry)); + } + } + pstServiceFlowEntry->bUsed = false; + pstServiceFlowEntry->uiVcid = 0; + } + + return 0; +} + +/* + * PhsCompress + * + * Routine Description: + * Exported function to compress the data using PHS. + * + * Arguments: + * IN void* pvContext - PHS Driver Specific Context. + * IN B_UINT16 uiVcid - The Service Flow ID to which current packet header compression applies. + * IN UINT uiClsId - The Classifier ID to which current packet header compression applies. + * IN void *pvInputBuffer - The Input buffer containg packet header data + * IN void *pvOutputBuffer - The output buffer returned by this function after PHS + * IN UINT *pOldHeaderSize - The actual size of the header before PHS + * IN UINT *pNewHeaderSize - The new size of the header after applying PHS + * + * Return Value: + * + * 0 if successful, + * >0 Error. + */ +static ULONG PhsCompress(IN void *pvContext, + IN B_UINT16 uiVcid, + IN B_UINT16 uiClsId, + IN void *pvInputBuffer, + OUT void *pvOutputBuffer, + OUT UINT *pOldHeaderSize, + OUT UINT *pNewHeaderSize) +{ + UINT nSFIndex = 0, nClsidIndex = 0; + struct bcm_phs_entry *pstServiceFlowEntry = NULL; + struct bcm_phs_classifier_entry *pstClassifierEntry = NULL; + struct bcm_phs_rule *pstPhsRule = NULL; + ULONG lStatus = 0; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext; + + if (pDeviceExtension == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "Invalid Device Extension\n"); + lStatus = STATUS_PHS_NOCOMPRESSION; + return lStatus; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "Suppressing header\n"); + + /* Retrieve the SFID Entry Index for requested Service Flow */ + nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable, + uiVcid, &pstServiceFlowEntry); + if (nSFIndex == PHS_INVALID_TABLE_INDEX) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "SFID Match Failed\n"); + lStatus = STATUS_PHS_NOCOMPRESSION; + return lStatus; + } + + nClsidIndex = GetClassifierEntry(pstServiceFlowEntry->pstClassifierTable, + uiClsId, eActiveClassifierRuleContext, &pstClassifierEntry); + + if (nClsidIndex == PHS_INVALID_TABLE_INDEX) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "No PHS Rule Defined For Classifier\n"); + lStatus = STATUS_PHS_NOCOMPRESSION; + return lStatus; + } + + /* get rule from SF id,Cls ID pair and proceed */ + pstPhsRule = pstClassifierEntry->pstPhsRule; + if (!ValidatePHSRuleComplete(pstPhsRule)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "PHS Rule Defined For Classifier But Not Complete\n"); + lStatus = STATUS_PHS_NOCOMPRESSION; + return lStatus; + } + + /* Compress Packet */ + lStatus = phs_compress(pstPhsRule, (PUCHAR)pvInputBuffer, + (PUCHAR)pvOutputBuffer, pOldHeaderSize, pNewHeaderSize); + + if (lStatus == STATUS_PHS_COMPRESSED) { + pstPhsRule->PHSModifiedBytes += *pOldHeaderSize - *pNewHeaderSize - 1; + pstPhsRule->PHSModifiedNumPackets++; + } else + pstPhsRule->PHSErrorNumPackets++; + + return lStatus; +} + +/* + * PhsDeCompress + * + * Routine Description: + * Exported function to restore the packet header in Rx path. + * + * Arguments: + * IN void* pvContext - PHS Driver Specific Context. + * IN B_UINT16 uiVcid - The Service Flow ID to which current packet header restoration applies. + * IN void *pvInputBuffer - The Input buffer containg suppressed packet header data + * OUT void *pvOutputBuffer - The output buffer returned by this function after restoration + * OUT UINT *pHeaderSize - The packet header size after restoration is returned in this parameter. + * + * Return Value: + * + * 0 if successful, + * >0 Error. + */ +static ULONG PhsDeCompress(IN void *pvContext, + IN B_UINT16 uiVcid, + IN void *pvInputBuffer, + OUT void *pvOutputBuffer, + OUT UINT *pInHeaderSize, + OUT UINT *pOutHeaderSize) +{ + UINT nSFIndex = 0, nPhsRuleIndex = 0; + struct bcm_phs_entry *pstServiceFlowEntry = NULL; + struct bcm_phs_rule *pstPhsRule = NULL; + UINT phsi; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + struct bcm_phs_extension *pDeviceExtension = (struct bcm_phs_extension *)pvContext; + + *pInHeaderSize = 0; + if (pDeviceExtension == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "Invalid Device Extension\n"); + return ERR_PHS_INVALID_DEVICE_EXETENSION; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "Restoring header\n"); + + phsi = *((unsigned char *)(pvInputBuffer)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "PHSI To Be Used For restore : %x\n", phsi); + if (phsi == UNCOMPRESSED_PACKET) + return STATUS_PHS_NOCOMPRESSION; + + /* Retrieve the SFID Entry Index for requested Service Flow */ + nSFIndex = GetServiceFlowEntry(pDeviceExtension->pstServiceFlowPhsRulesTable, + uiVcid, &pstServiceFlowEntry); + if (nSFIndex == PHS_INVALID_TABLE_INDEX) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "SFID Match Failed During Lookup\n"); + return ERR_SF_MATCH_FAIL; + } + + nPhsRuleIndex = GetPhsRuleEntry(pstServiceFlowEntry->pstClassifierTable, phsi, + eActiveClassifierRuleContext, &pstPhsRule); + if (nPhsRuleIndex == PHS_INVALID_TABLE_INDEX) { + /* Phs Rule does not exist in active rules table. Lets try in the old rules table. */ + nPhsRuleIndex = GetPhsRuleEntry(pstServiceFlowEntry->pstClassifierTable, + phsi, eOldClassifierRuleContext, &pstPhsRule); + if (nPhsRuleIndex == PHS_INVALID_TABLE_INDEX) + return ERR_PHSRULE_MATCH_FAIL; + } + + *pInHeaderSize = phs_decompress((PUCHAR)pvInputBuffer, + (PUCHAR)pvOutputBuffer, pstPhsRule, pOutHeaderSize); + + pstPhsRule->PHSModifiedBytes += *pOutHeaderSize - *pInHeaderSize - 1; + + pstPhsRule->PHSModifiedNumPackets++; + return STATUS_PHS_COMPRESSED; +} + +/* + * Procedure: free_phs_serviceflow_rules + * + * Description: This routine is responsible for freeing memory allocated for PHS rules. + * + * Arguments: + * rules - ptr to S_SERVICEFLOW_TABLE structure. + * + * Returns: + * Does not return any value. + */ +static void free_phs_serviceflow_rules(struct bcm_phs_table *psServiceFlowRulesTable) +{ + int i, j; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "=======>\n"); + + if (psServiceFlowRulesTable) { + for (i = 0; i < MAX_SERVICEFLOWS; i++) { + struct bcm_phs_entry stServiceFlowEntry = psServiceFlowRulesTable->stSFList[i]; + struct bcm_phs_classifier_table *pstClassifierRulesTable = stServiceFlowEntry.pstClassifierTable; + + if (pstClassifierRulesTable) { + for (j = 0; j < MAX_PHSRULE_PER_SF; j++) { + if (pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule) { + + if (pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule->u8RefCnt) + pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule->u8RefCnt--; + + if (0 == pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule->u8RefCnt) + kfree(pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule); + + pstClassifierRulesTable->stActivePhsRulesList[j].pstPhsRule = NULL; + } + + if (pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule) { + + if (pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule->u8RefCnt) + pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule->u8RefCnt--; + + if (0 == pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule->u8RefCnt) + kfree(pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule); + + pstClassifierRulesTable->stOldPhsRulesList[j].pstPhsRule = NULL; + } + } + kfree(pstClassifierRulesTable); + stServiceFlowEntry.pstClassifierTable = pstClassifierRulesTable = NULL; + } + } + } + + kfree(psServiceFlowRulesTable); + psServiceFlowRulesTable = NULL; +} + +static bool ValidatePHSRuleComplete(IN struct bcm_phs_rule *psPhsRule) +{ + if (psPhsRule) { + if (!psPhsRule->u8PHSI) { + /* PHSI is not valid */ + return false; + } + + if (!psPhsRule->u8PHSS) { + /* PHSS Is Undefined */ + return false; + } + + /* Check if PHSF is defines for the PHS Rule */ + if (!psPhsRule->u8PHSFLength) /* If any part of PHSF is valid then Rule contains valid PHSF */ + return false; + + return TRUE; + } else + return false; +} + +UINT GetServiceFlowEntry(IN struct bcm_phs_table *psServiceFlowTable, + IN B_UINT16 uiVcid, + struct bcm_phs_entry **ppstServiceFlowEntry) +{ + int i; + + for (i = 0; i < MAX_SERVICEFLOWS; i++) { + if (psServiceFlowTable->stSFList[i].bUsed) { + if (psServiceFlowTable->stSFList[i].uiVcid == uiVcid) { + *ppstServiceFlowEntry = &psServiceFlowTable->stSFList[i]; + return i; + } + } + } + + *ppstServiceFlowEntry = NULL; + return PHS_INVALID_TABLE_INDEX; +} + +static UINT GetClassifierEntry(IN struct bcm_phs_classifier_table *pstClassifierTable, + IN B_UINT32 uiClsid, enum bcm_phs_classifier_context eClsContext, + OUT struct bcm_phs_classifier_entry **ppstClassifierEntry) +{ + int i; + struct bcm_phs_classifier_entry *psClassifierRules = NULL; + + for (i = 0; i < MAX_PHSRULE_PER_SF; i++) { + + if (eClsContext == eActiveClassifierRuleContext) + psClassifierRules = &pstClassifierTable->stActivePhsRulesList[i]; + else + psClassifierRules = &pstClassifierTable->stOldPhsRulesList[i]; + + if (psClassifierRules->bUsed) { + if (psClassifierRules->uiClassifierRuleId == uiClsid) { + *ppstClassifierEntry = psClassifierRules; + return i; + } + } + } + + *ppstClassifierEntry = NULL; + return PHS_INVALID_TABLE_INDEX; +} + +static UINT GetPhsRuleEntry(IN struct bcm_phs_classifier_table *pstClassifierTable, + IN B_UINT32 uiPHSI, enum bcm_phs_classifier_context eClsContext, + OUT struct bcm_phs_rule **ppstPhsRule) +{ + int i; + struct bcm_phs_classifier_entry *pstClassifierRule = NULL; + + for (i = 0; i < MAX_PHSRULE_PER_SF; i++) { + if (eClsContext == eActiveClassifierRuleContext) + pstClassifierRule = &pstClassifierTable->stActivePhsRulesList[i]; + else + pstClassifierRule = &pstClassifierTable->stOldPhsRulesList[i]; + + if (pstClassifierRule->bUsed) { + if (pstClassifierRule->u8PHSI == uiPHSI) { + *ppstPhsRule = pstClassifierRule->pstPhsRule; + return i; + } + } + } + + *ppstPhsRule = NULL; + return PHS_INVALID_TABLE_INDEX; +} + +static UINT CreateSFToClassifierRuleMapping(IN B_UINT16 uiVcid, IN B_UINT16 uiClsId, + IN struct bcm_phs_table *psServiceFlowTable, + struct bcm_phs_rule *psPhsRule, + B_UINT8 u8AssociatedPHSI) +{ + struct bcm_phs_classifier_table *psaClassifiertable = NULL; + UINT uiStatus = 0; + int iSfIndex; + bool bFreeEntryFound = false; + + /* Check for a free entry in SFID table */ + for (iSfIndex = 0; iSfIndex < MAX_SERVICEFLOWS; iSfIndex++) { + if (!psServiceFlowTable->stSFList[iSfIndex].bUsed) { + bFreeEntryFound = TRUE; + break; + } + } + + if (!bFreeEntryFound) + return ERR_SFTABLE_FULL; + + psaClassifiertable = psServiceFlowTable->stSFList[iSfIndex].pstClassifierTable; + uiStatus = CreateClassifierPHSRule(uiClsId, psaClassifiertable, psPhsRule, + eActiveClassifierRuleContext, u8AssociatedPHSI); + if (uiStatus == PHS_SUCCESS) { + /* Add entry at free index to the SF */ + psServiceFlowTable->stSFList[iSfIndex].bUsed = TRUE; + psServiceFlowTable->stSFList[iSfIndex].uiVcid = uiVcid; + } + + return uiStatus; +} + +static UINT CreateClassiferToPHSRuleMapping(IN B_UINT16 uiVcid, + IN B_UINT16 uiClsId, + IN struct bcm_phs_entry *pstServiceFlowEntry, + struct bcm_phs_rule *psPhsRule, + B_UINT8 u8AssociatedPHSI) +{ + struct bcm_phs_classifier_entry *pstClassifierEntry = NULL; + UINT uiStatus = PHS_SUCCESS; + UINT nClassifierIndex = 0; + struct bcm_phs_classifier_table *psaClassifiertable = NULL; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + psaClassifiertable = pstServiceFlowEntry->pstClassifierTable; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "==>"); + + /* Check if the supplied Classifier already exists */ + nClassifierIndex = GetClassifierEntry( + pstServiceFlowEntry->pstClassifierTable, + uiClsId, + eActiveClassifierRuleContext, + &pstClassifierEntry); + + if (nClassifierIndex == PHS_INVALID_TABLE_INDEX) { + /* + * The Classifier doesn't exist. So its a new classifier being added. + * Add new entry to associate PHS Rule to the Classifier + */ + + uiStatus = CreateClassifierPHSRule(uiClsId, psaClassifiertable, + psPhsRule, + eActiveClassifierRuleContext, + u8AssociatedPHSI); + return uiStatus; + } + + /* + * The Classifier exists.The PHS Rule for this classifier + * is being modified + */ + + if (pstClassifierEntry->u8PHSI == psPhsRule->u8PHSI) { + if (pstClassifierEntry->pstPhsRule == NULL) + return ERR_PHS_INVALID_PHS_RULE; + + /* + * This rule already exists if any fields are changed for this PHS + * rule update them. + */ + /* If any part of PHSF is valid then we update PHSF */ + if (psPhsRule->u8PHSFLength) { + /* update PHSF */ + memcpy(pstClassifierEntry->pstPhsRule->u8PHSF, + psPhsRule->u8PHSF, MAX_PHS_LENGTHS); + } + + if (psPhsRule->u8PHSFLength) { + /* update PHSFLen */ + pstClassifierEntry->pstPhsRule->u8PHSFLength = psPhsRule->u8PHSFLength; + } + + if (psPhsRule->u8PHSMLength) { + /* update PHSM */ + memcpy(pstClassifierEntry->pstPhsRule->u8PHSM, + psPhsRule->u8PHSM, MAX_PHS_LENGTHS); + } + + if (psPhsRule->u8PHSMLength) { + /* update PHSM Len */ + pstClassifierEntry->pstPhsRule->u8PHSMLength = + psPhsRule->u8PHSMLength; + } + + if (psPhsRule->u8PHSS) { + /* update PHSS */ + pstClassifierEntry->pstPhsRule->u8PHSS = psPhsRule->u8PHSS; + } + + /* update PHSV */ + pstClassifierEntry->pstPhsRule->u8PHSV = psPhsRule->u8PHSV; + } else { + /* A new rule is being set for this classifier. */ + uiStatus = UpdateClassifierPHSRule(uiClsId, pstClassifierEntry, + psaClassifiertable, psPhsRule, u8AssociatedPHSI); + } + + return uiStatus; +} + +static UINT CreateClassifierPHSRule(IN B_UINT16 uiClsId, + struct bcm_phs_classifier_table *psaClassifiertable, + struct bcm_phs_rule *psPhsRule, + enum bcm_phs_classifier_context eClsContext, + B_UINT8 u8AssociatedPHSI) +{ + UINT iClassifierIndex = 0; + bool bFreeEntryFound = false; + struct bcm_phs_classifier_entry *psClassifierRules = NULL; + UINT nStatus = PHS_SUCCESS; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "Inside CreateClassifierPHSRule"); + + if (psaClassifiertable == NULL) + return ERR_INVALID_CLASSIFIERTABLE_FOR_SF; + + if (eClsContext == eOldClassifierRuleContext) { + /* + * If An Old Entry for this classifier ID already exists in the + * old rules table replace it. + */ + + iClassifierIndex = + GetClassifierEntry(psaClassifiertable, uiClsId, + eClsContext, &psClassifierRules); + + if (iClassifierIndex != PHS_INVALID_TABLE_INDEX) { + /* + * The Classifier already exists in the old rules table + * Lets replace the old classifier with the new one. + */ + bFreeEntryFound = TRUE; + } + } + + if (!bFreeEntryFound) { + /* Continue to search for a free location to add the rule */ + for (iClassifierIndex = 0; iClassifierIndex < + MAX_PHSRULE_PER_SF; iClassifierIndex++) { + if (eClsContext == eActiveClassifierRuleContext) + psClassifierRules = &psaClassifiertable->stActivePhsRulesList[iClassifierIndex]; + else + psClassifierRules = &psaClassifiertable->stOldPhsRulesList[iClassifierIndex]; + + if (!psClassifierRules->bUsed) { + bFreeEntryFound = TRUE; + break; + } + } + } + + if (!bFreeEntryFound) { + + if (eClsContext == eActiveClassifierRuleContext) + return ERR_CLSASSIFIER_TABLE_FULL; + else { + /* Lets replace the oldest rule if we are looking in old Rule table */ + if (psaClassifiertable->uiOldestPhsRuleIndex >= MAX_PHSRULE_PER_SF) + psaClassifiertable->uiOldestPhsRuleIndex = 0; + + iClassifierIndex = psaClassifiertable->uiOldestPhsRuleIndex; + psClassifierRules = &psaClassifiertable->stOldPhsRulesList[iClassifierIndex]; + + (psaClassifiertable->uiOldestPhsRuleIndex)++; + } + } + + if (eClsContext == eOldClassifierRuleContext) { + + if (psClassifierRules->pstPhsRule == NULL) { + + psClassifierRules->pstPhsRule = kmalloc(sizeof(struct bcm_phs_rule), GFP_KERNEL); + + if (NULL == psClassifierRules->pstPhsRule) + return ERR_PHSRULE_MEMALLOC_FAIL; + } + + psClassifierRules->bUsed = TRUE; + psClassifierRules->uiClassifierRuleId = uiClsId; + psClassifierRules->u8PHSI = psPhsRule->u8PHSI; + psClassifierRules->bUnclassifiedPHSRule = psPhsRule->bUnclassifiedPHSRule; + + /* Update The PHS rule */ + memcpy(psClassifierRules->pstPhsRule, psPhsRule, sizeof(struct bcm_phs_rule)); + } else + nStatus = UpdateClassifierPHSRule(uiClsId, psClassifierRules, + psaClassifiertable, psPhsRule, u8AssociatedPHSI); + + return nStatus; +} + +static UINT UpdateClassifierPHSRule(IN B_UINT16 uiClsId, + IN struct bcm_phs_classifier_entry *pstClassifierEntry, + struct bcm_phs_classifier_table *psaClassifiertable, + struct bcm_phs_rule *psPhsRule, + B_UINT8 u8AssociatedPHSI) +{ + struct bcm_phs_rule *pstAddPhsRule = NULL; + UINT nPhsRuleIndex = 0; + bool bPHSRuleOrphaned = false; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + psPhsRule->u8RefCnt = 0; + + /* Step 1 Deref Any Exisiting PHS Rule in this classifier Entry */ + bPHSRuleOrphaned = DerefPhsRule(uiClsId, psaClassifiertable, + pstClassifierEntry->pstPhsRule); + + /* Step 2 Search if there is a PHS Rule with u8AssociatedPHSI in Classifier table for this SF */ + nPhsRuleIndex = GetPhsRuleEntry(psaClassifiertable, u8AssociatedPHSI, + eActiveClassifierRuleContext, &pstAddPhsRule); + if (PHS_INVALID_TABLE_INDEX == nPhsRuleIndex) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nAdding New PHSRuleEntry For Classifier"); + + if (psPhsRule->u8PHSI == 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nError PHSI is Zero\n"); + return ERR_PHS_INVALID_PHS_RULE; + } + + /* Step 2.a PHS Rule Does Not Exist .Create New PHS Rule for uiClsId */ + if (false == bPHSRuleOrphaned) { + + pstClassifierEntry->pstPhsRule = kmalloc(sizeof(struct bcm_phs_rule), GFP_KERNEL); + if (NULL == pstClassifierEntry->pstPhsRule) + return ERR_PHSRULE_MEMALLOC_FAIL; + } + memcpy(pstClassifierEntry->pstPhsRule, psPhsRule, sizeof(struct bcm_phs_rule)); + } else { + /* Step 2.b PHS Rule Exists Tie uiClsId with the existing PHS Rule */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\nTying Classifier to Existing PHS Rule"); + if (bPHSRuleOrphaned) { + kfree(pstClassifierEntry->pstPhsRule); + pstClassifierEntry->pstPhsRule = NULL; + } + pstClassifierEntry->pstPhsRule = pstAddPhsRule; + } + + pstClassifierEntry->bUsed = TRUE; + pstClassifierEntry->u8PHSI = pstClassifierEntry->pstPhsRule->u8PHSI; + pstClassifierEntry->uiClassifierRuleId = uiClsId; + pstClassifierEntry->pstPhsRule->u8RefCnt++; + pstClassifierEntry->bUnclassifiedPHSRule = pstClassifierEntry->pstPhsRule->bUnclassifiedPHSRule; + + return PHS_SUCCESS; +} + +static bool DerefPhsRule(IN B_UINT16 uiClsId, struct bcm_phs_classifier_table *psaClassifiertable, struct bcm_phs_rule *pstPhsRule) +{ + if (pstPhsRule == NULL) + return false; + + if (pstPhsRule->u8RefCnt) + pstPhsRule->u8RefCnt--; + + if (0 == pstPhsRule->u8RefCnt) { + /* + * if(pstPhsRule->u8PHSI) + * Store the currently active rule into the old rules list + * CreateClassifierPHSRule(uiClsId,psaClassifiertable,pstPhsRule,eOldClassifierRuleContext,pstPhsRule->u8PHSI); + */ + return TRUE; + } else + return false; +} + +void DumpPhsRules(struct bcm_phs_extension *pDeviceExtension) +{ + int i, j, k, l; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n Dumping PHS Rules :\n"); + + for (i = 0; i < MAX_SERVICEFLOWS; i++) { + + struct bcm_phs_entry stServFlowEntry = + pDeviceExtension->pstServiceFlowPhsRulesTable->stSFList[i]; + if (stServFlowEntry.bUsed) { + + for (j = 0; j < MAX_PHSRULE_PER_SF; j++) { + + for (l = 0; l < 2; l++) { + struct bcm_phs_classifier_entry stClsEntry; + + if (l == 0) { + stClsEntry = stServFlowEntry.pstClassifierTable->stActivePhsRulesList[j]; + if (stClsEntry.bUsed) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n Active PHS Rule :\n"); + } else { + stClsEntry = stServFlowEntry.pstClassifierTable->stOldPhsRulesList[j]; + if (stClsEntry.bUsed) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n Old PHS Rule :\n"); + } + + if (stClsEntry.bUsed) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n VCID : %#X", stServFlowEntry.uiVcid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n ClassifierID : %#X", stClsEntry.uiClassifierRuleId); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSRuleID : %#X", stClsEntry.u8PHSI); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n****************PHS Rule********************\n"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSI : %#X", stClsEntry.pstPhsRule->u8PHSI); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSFLength : %#X ", stClsEntry.pstPhsRule->u8PHSFLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSF : "); + + for (k = 0 ; k < stClsEntry.pstPhsRule->u8PHSFLength; k++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "%#X ", stClsEntry.pstPhsRule->u8PHSF[k]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSMLength : %#X", stClsEntry.pstPhsRule->u8PHSMLength); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSM :"); + + for (k = 0; k < stClsEntry.pstPhsRule->u8PHSMLength; k++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "%#X ", stClsEntry.pstPhsRule->u8PHSM[k]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSS : %#X ", stClsEntry.pstPhsRule->u8PHSS); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, (DBG_LVL_ALL|DBG_NO_FUNC_PRINT), "\n PHSV : %#X", stClsEntry.pstPhsRule->u8PHSV); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "\n********************************************\n"); + } + } + } + } + } +} + +/* + * Procedure: phs_decompress + * + * Description: This routine restores the static fields within the packet. + * + * Arguments: + * in_buf - ptr to incoming packet buffer. + * out_buf - ptr to output buffer where the suppressed header is copied. + * decomp_phs_rules - ptr to PHS rule. + * header_size - ptr to field which holds the phss or phsf_length. + * + * Returns: + * size -The number of bytes of dynamic fields present with in the incoming packet + * header. + * 0 -If PHS rule is NULL.If PHSI is 0 indicateing packet as uncompressed. + */ +static int phs_decompress(unsigned char *in_buf, + unsigned char *out_buf, + struct bcm_phs_rule *decomp_phs_rules, + UINT *header_size) +{ + int phss, size = 0; + struct bcm_phs_rule *tmp_memb; + int bit, i = 0; + unsigned char *phsf, *phsm; + int in_buf_len = *header_size - 1; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + in_buf++; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "====>\n"); + *header_size = 0; + + if ((decomp_phs_rules == NULL)) + return 0; + + tmp_memb = decomp_phs_rules; + /* + * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP:In phs_decompress PHSI 1 %d",phsi)); + * header_size = tmp_memb->u8PHSFLength; + */ + phss = tmp_memb->u8PHSS; + phsf = tmp_memb->u8PHSF; + phsm = tmp_memb->u8PHSM; + + if (phss > MAX_PHS_LENGTHS) + phss = MAX_PHS_LENGTHS; + + /* + * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_RECEIVE,DBG_LVL_ALL,"\nDECOMP: + * In phs_decompress PHSI %d phss %d index %d",phsi,phss,index)); + */ + while ((phss > 0) && (size < in_buf_len)) { + bit = ((*phsm << i) & SUPPRESS); + + if (bit == SUPPRESS) { + *out_buf = *phsf; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "\nDECOMP:In phss %d phsf %d output %d", + phss, *phsf, *out_buf); + } else { + *out_buf = *in_buf; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_RECEIVE, DBG_LVL_ALL, "\nDECOMP:In phss %d input %d output %d", + phss, *in_buf, *out_buf); + in_buf++; + size++; + } + out_buf++; + phsf++; + phss--; + i++; + *header_size = *header_size + 1; + + if (i > MAX_NO_BIT) { + i = 0; + phsm++; + } + } + + return size; +} + +/* + * Procedure: phs_compress + * + * Description: This routine suppresses the static fields within the packet.Before + * that it will verify the fields to be suppressed with the corresponding fields in the + * phsf. For verification it checks the phsv field of PHS rule. If set and verification + * succeeds it suppresses the field.If any one static field is found different none of + * the static fields are suppressed then the packet is sent as uncompressed packet with + * phsi=0. + * + * Arguments: + * phs_rule - ptr to PHS rule. + * in_buf - ptr to incoming packet buffer. + * out_buf - ptr to output buffer where the suppressed header is copied. + * header_size - ptr to field which holds the phss. + * + * Returns: + * size-The number of bytes copied into the output buffer i.e dynamic fields + * 0 -If PHS rule is NULL.If PHSV field is not set.If the verification fails. + */ +static int phs_compress(struct bcm_phs_rule *phs_rule, + unsigned char *in_buf, + unsigned char *out_buf, + UINT *header_size, + UINT *new_header_size) +{ + unsigned char *old_addr = out_buf; + int suppress = 0; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + if (phs_rule == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nphs_compress(): phs_rule null!"); + *out_buf = ZERO_PHSI; + return STATUS_PHS_NOCOMPRESSION; + } + + if (phs_rule->u8PHSS <= *new_header_size) + *header_size = phs_rule->u8PHSS; + else + *header_size = *new_header_size; + + /* To copy PHSI */ + out_buf++; + suppress = verify_suppress_phsf(in_buf, out_buf, phs_rule->u8PHSF, + phs_rule->u8PHSM, phs_rule->u8PHSS, + phs_rule->u8PHSV, new_header_size); + + if (suppress == STATUS_PHS_COMPRESSED) { + *old_addr = (unsigned char)phs_rule->u8PHSI; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nCOMP:In phs_compress phsi %d", phs_rule->u8PHSI); + } else { + *old_addr = ZERO_PHSI; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nCOMP:In phs_compress PHSV Verification failed"); + } + + return suppress; +} + +/* + * Procedure: verify_suppress_phsf + * + * Description: This routine verifies the fields of the packet and if all the + * static fields are equal it adds the phsi of that PHS rule.If any static + * field differs it woun't suppress any field. + * + * Arguments: + * rules_set - ptr to classifier_rules. + * in_buffer - ptr to incoming packet buffer. + * out_buffer - ptr to output buffer where the suppressed header is copied. + * phsf - ptr to phsf. + * phsm - ptr to phsm. + * phss - variable holding phss. + * + * Returns: + * size-The number of bytes copied into the output buffer i.e dynamic fields. + * 0 -Packet has failed the verification. + */ +static int verify_suppress_phsf(unsigned char *in_buffer, + unsigned char *out_buffer, + unsigned char *phsf, + unsigned char *phsm, + unsigned int phss, + unsigned int phsv, + UINT *new_header_size) +{ + unsigned int size = 0; + int bit, i = 0; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nCOMP:In verify_phsf PHSM - 0x%X", *phsm); + + if (phss > (*new_header_size)) + phss = *new_header_size; + + while (phss > 0) { + bit = ((*phsm << i) & SUPPRESS); + if (bit == SUPPRESS) { + if (*in_buffer != *phsf) { + if (phsv == VERIFY) { + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, + PHS_SEND, + DBG_LVL_ALL, + "\nCOMP:In verify_phsf failed for field %d buf %d phsf %d", + phss, + *in_buffer, + *phsf); + return STATUS_PHS_NOCOMPRESSION; + } + } else + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, + PHS_SEND, + DBG_LVL_ALL, + "\nCOMP:In verify_phsf success for field %d buf %d phsf %d", + phss, + *in_buffer, + *phsf); + } else { + *out_buffer = *in_buffer; + BCM_DEBUG_PRINT(Adapter, + DBG_TYPE_OTHERS, + PHS_SEND, + DBG_LVL_ALL, + "\nCOMP:In copying_header input %d out %d", + *in_buffer, + *out_buffer); + out_buffer++; + size++; + } + + in_buffer++; + phsf++; + phss--; + i++; + + if (i > MAX_NO_BIT) { + i = 0; + phsm++; + } + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, PHS_SEND, DBG_LVL_ALL, "\nCOMP:In verify_phsf success"); + *new_header_size = size; + return STATUS_PHS_COMPRESSED; +} diff --git a/drivers/staging/bcm/PHSModule.h b/drivers/staging/bcm/PHSModule.h new file mode 100644 index 00000000000..d697f9c860c --- /dev/null +++ b/drivers/staging/bcm/PHSModule.h @@ -0,0 +1,50 @@ +#ifndef BCM_MINIPORT_PHSMODULE_H +#define BCM_MINIPORT_PHSMODULE_H + +int PHSTransmit(struct bcm_mini_adapter *Adapter, + struct sk_buff **pPacket, + USHORT Vcid, + B_UINT16 uiClassifierRuleID, + bool bHeaderSuppressionEnabled, + PUINT PacketLen, + UCHAR bEthCSSupport); + +int PHSReceive(struct bcm_mini_adapter *Adapter, + USHORT usVcid, + struct sk_buff *packet, + UINT *punPacketLen, + UCHAR *pucEthernetHdr, + UINT + ); + + +void DumpDataPacketHeader(PUCHAR pPkt); + +void DumpFullPacket(UCHAR *pBuf,UINT nPktLen); + +void DumpPhsRules(struct bcm_phs_extension *pDeviceExtension); + + +int phs_init(struct bcm_phs_extension *pPhsdeviceExtension,struct bcm_mini_adapter *Adapter); + +int PhsCleanup(struct bcm_phs_extension *pPHSDeviceExt); + +//Utility Functions +ULONG PhsUpdateClassifierRule(void* pvContext,B_UINT16 uiVcid,B_UINT16 uiClsId, struct bcm_phs_rule *psPhsRule,B_UINT8 u8AssociatedPHSI ); + +ULONG PhsDeletePHSRule(void* pvContext,B_UINT16 uiVcid,B_UINT8 u8PHSI); + +ULONG PhsDeleteClassifierRule(void* pvContext, B_UINT16 uiVcid ,B_UINT16 uiClsId); + +ULONG PhsDeleteSFRules(void* pvContext,B_UINT16 uiVcid) ; + + +bool ValidatePHSRule(struct bcm_phs_rule *psPhsRule); + +UINT GetServiceFlowEntry(struct bcm_phs_table *psServiceFlowTable,B_UINT16 uiVcid, struct bcm_phs_entry **ppstServiceFlowEntry); + + +void DumpPhsRules(struct bcm_phs_extension *pDeviceExtension); + + +#endif diff --git a/drivers/staging/bcm/Protocol.h b/drivers/staging/bcm/Protocol.h new file mode 100644 index 00000000000..9818128d932 --- /dev/null +++ b/drivers/staging/bcm/Protocol.h @@ -0,0 +1,128 @@ +/************************************ +* Protocol.h +*************************************/ +#ifndef __PROTOCOL_H__ +#define __PROTOCOL_H__ + +#define IPV4 4 +#define IPV6 6 + +struct ArpHeader { + struct arphdr arp; + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + unsigned char ar_sip[4]; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + unsigned char ar_tip[4]; /* target IP address */ +}; + +struct bcm_transport_header { + union { + struct udphdr uhdr; + struct tcphdr thdr; + }; +} __packed; + +enum bcm_ip_frame_type { + eNonIPPacket, + eIPv4Packet, + eIPv6Packet +}; + +enum bcm_eth_frame_type { + eEthUnsupportedFrame, + eEth802LLCFrame, + eEth802LLCSNAPFrame, + eEth802QVLANFrame, + eEthOtherFrame +}; + +struct bcm_eth_packet_info { + enum bcm_ip_frame_type eNwpktIPFrameType; + enum bcm_eth_frame_type eNwpktEthFrameType; + unsigned short usEtherType; + unsigned char ucDSAP; +}; + +struct bcm_eth_q_frame { + struct bcm_eth_header EThHdr; + unsigned short UserPriority:3; + unsigned short CFI:1; + unsigned short VLANID:12; + unsigned short EthType; +} __packed; + +struct bcm_eth_llc_frame { + struct bcm_eth_header EThHdr; + unsigned char DSAP; + unsigned char SSAP; + unsigned char Control; +} __packed; + +struct bcm_eth_llc_snap_frame { + struct bcm_eth_header EThHdr; + unsigned char DSAP; + unsigned char SSAP; + unsigned char Control; + unsigned char OUI[3]; + unsigned short usEtherType; +} __packed; + +struct bcm_ethernet2_frame { + struct bcm_eth_header EThHdr; +} __packed; + +#define ETHERNET_FRAMETYPE_IPV4 ntohs(0x0800) +#define ETHERNET_FRAMETYPE_IPV6 ntohs(0x86dd) +#define ETHERNET_FRAMETYPE_802QVLAN ntohs(0x8100) + +/* Per SF CS Specification Encodings */ +enum bcm_spec_encoding { + eCSSpecUnspecified = 0, + eCSPacketIPV4, + eCSPacketIPV6, + eCS802_3PacketEthernet, + eCS802_1QPacketVLAN, + eCSPacketIPV4Over802_3Ethernet, + eCSPacketIPV6Over802_3Ethernet, + eCSPacketIPV4Over802_1QVLAN, + eCSPacketIPV6Over802_1QVLAN, + eCSPacketUnsupported +}; + +#define IP6_HEADER_LEN 40 +#define IP_VERSION(byte) (((byte&0xF0)>>4)) + +#define MAC_ADDRESS_SIZE 6 +#define ETH_AND_IP_HEADER_LEN (14 + 20) +#define L4_SRC_PORT_LEN 2 +#define L4_DEST_PORT_LEN 2 +#define CTRL_PKT_LEN (8 + ETH_AND_IP_HEADER_LEN) + +#define ETH_ARP_FRAME 0x806 +#define ETH_IPV4_FRAME 0x800 +#define ETH_IPV6_FRAME 0x86DD +#define UDP 0x11 +#define TCP 0x06 + +#define ARP_OP_REQUEST 0x01 +#define ARP_OP_REPLY 0x02 +#define ARP_PKT_SIZE 60 + +/* This is the format for the TCP packet header */ +struct bcm_tcp_header { + unsigned short usSrcPort; + unsigned short usDestPort; + unsigned long ulSeqNumber; + unsigned long ulAckNumber; + unsigned char HeaderLength; + unsigned char ucFlags; + unsigned short usWindowsSize; + unsigned short usChkSum; + unsigned short usUrgetPtr; +}; + +#define TCP_HEADER_LEN sizeof(struct bcm_tcp_header) +#define TCP_ACK 0x10 /* Bit 4 in tcpflags field. */ +#define GET_TCP_HEADER_LEN(byte) ((byte&0xF0)>>4) + +#endif /* __PROTOCOL_H__ */ diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h new file mode 100644 index 00000000000..fb53a00591e --- /dev/null +++ b/drivers/staging/bcm/Prototypes.h @@ -0,0 +1,222 @@ +#ifndef _PROTOTYPES_H_ +#define _PROTOTYPES_H_ + +VOID LinkControlResponseMessage(struct bcm_mini_adapter *Adapter, PUCHAR pucBuffer); + +VOID StatisticsResponse(struct bcm_mini_adapter *Adapter,PVOID pvBuffer); + +VOID IdleModeResponse(struct bcm_mini_adapter *Adapter,PUINT puiBuffer); + +int control_packet_handler (struct bcm_mini_adapter *Adapter); + +VOID DeleteAllClassifiersForSF(struct bcm_mini_adapter *Adapter,UINT uiSearchRuleIndex); + +VOID flush_all_queues(struct bcm_mini_adapter *Adapter); + +int register_control_device_interface(struct bcm_mini_adapter *ps_adapter); + +void unregister_control_device_interface(struct bcm_mini_adapter *Adapter); + +INT CopyBufferToControlPacket(struct bcm_mini_adapter *Adapter,/**<Logical Adapter*/ + PVOID ioBuffer/**<Control Packet Buffer*/ + ); + +VOID SortPackInfo(struct bcm_mini_adapter *Adapter); + +VOID SortClassifiers(struct bcm_mini_adapter *Adapter); + +VOID flush_all_queues(struct bcm_mini_adapter *Adapter); + +VOID PruneQueueAllSF(struct bcm_mini_adapter *Adapter); + +INT SearchSfid(struct bcm_mini_adapter *Adapter,UINT uiSfid); + +USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter,struct sk_buff* skb); + +bool MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule,USHORT ushSrcPort); +bool MatchDestPort(struct bcm_classifier_rule *pstClassifierRule,USHORT ushSrcPort); +bool MatchProtocol(struct bcm_classifier_rule *pstClassifierRule,UCHAR ucProtocol); + + +INT SetupNextSend(struct bcm_mini_adapter *Adapter, /**<Logical Adapter*/ + struct sk_buff *Packet, /**<data buffer*/ + USHORT Vcid) ; + +VOID LinkMessage(struct bcm_mini_adapter *Adapter); + +VOID transmit_packets(struct bcm_mini_adapter *Adapter); + +INT SendControlPacket(struct bcm_mini_adapter *Adapter, /**<Logical Adapter*/ + char *pControlPacket/**<Control Packet*/ + ); + + +int register_networkdev(struct bcm_mini_adapter *Adapter); +void unregister_networkdev(struct bcm_mini_adapter *Adapter); + +INT AllocAdapterDsxBuffer(struct bcm_mini_adapter *Adapter); + +VOID AdapterFree(struct bcm_mini_adapter *Adapter); + +INT FreeAdapterDsxBuffer(struct bcm_mini_adapter *Adapter); + +int tx_pkt_handler(struct bcm_mini_adapter *Adapter); + +int reset_card_proc(struct bcm_mini_adapter *Adapter ); + +int run_card_proc(struct bcm_mini_adapter *Adapter ); + +int InitCardAndDownloadFirmware(struct bcm_mini_adapter *ps_adapter); + + +INT ReadMacAddressFromNVM(struct bcm_mini_adapter *Adapter); + +int register_control_device_interface(struct bcm_mini_adapter *ps_adapter); + +void DumpPackInfo(struct bcm_mini_adapter *Adapter); + +int rdm(struct bcm_mini_adapter *Adapter, UINT uiAddress, PCHAR pucBuff, size_t size); + +int wrm(struct bcm_mini_adapter *Adapter, UINT uiAddress, PCHAR pucBuff, size_t size); + +int wrmalt (struct bcm_mini_adapter *Adapter, UINT uiAddress, unsigned int *pucBuff, size_t sSize); + +int rdmalt (struct bcm_mini_adapter *Adapter, UINT uiAddress, unsigned int *pucBuff, size_t sSize); + +int get_dsx_sf_data_to_application(struct bcm_mini_adapter *Adapter, UINT uiSFId, void __user * user_buffer); + +void SendIdleModeResponse(struct bcm_mini_adapter *Adapter); + + +int ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, struct bcm_host_stats_mibs *buf); +void GetDroppedAppCntrlPktMibs(struct bcm_host_stats_mibs *ioBuffer, struct bcm_tarang_data *pTarang); +void beceem_parse_target_struct(struct bcm_mini_adapter *Adapter); + +int bcm_ioctl_fw_download(struct bcm_mini_adapter *Adapter, struct bcm_firmware_info *psFwInfo); + +void CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter, + struct bcm_connect_mgr_params *psfLocalSet, UINT uiSearchRuleIndex); + +VOID ResetCounters(struct bcm_mini_adapter *Adapter); + +int InitLedSettings(struct bcm_mini_adapter *Adapter); + +struct bcm_classifier_rule *GetFragIPClsEntry(struct bcm_mini_adapter *Adapter,USHORT usIpIdentification,ULONG SrcIP); + +void AddFragIPClsEntry(struct bcm_mini_adapter *Adapter, struct bcm_fragmented_packet_info *psFragPktInfo); + +void DelFragIPClsEntry(struct bcm_mini_adapter *Adapter,USHORT usIpIdentification,ULONG SrcIp); + +void update_per_cid_rx (struct bcm_mini_adapter *Adapter); + +void update_per_sf_desc_cnts( struct bcm_mini_adapter *Adapter); + +void ClearTargetDSXBuffer(struct bcm_mini_adapter *Adapter,B_UINT16 TID,bool bFreeAll); + + +void flush_queue(struct bcm_mini_adapter *Adapter, UINT iQIndex); + + +INT flushAllAppQ(VOID); + + +INT BeceemEEPROMBulkRead( + struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + UINT uiOffset, + UINT uiNumBytes); + + + +INT WriteBeceemEEPROM(struct bcm_mini_adapter *Adapter,UINT uiEEPROMOffset, UINT uiData); + +INT PropagateCalParamsFromFlashToMemory(struct bcm_mini_adapter *Adapter); + + +INT BeceemEEPROMBulkWrite( + struct bcm_mini_adapter *Adapter, + PUCHAR pBuffer, + UINT uiOffset, + UINT uiNumBytes, + bool bVerify); + + +INT ReadBeceemEEPROM(struct bcm_mini_adapter *Adapter,UINT dwAddress, UINT *pdwData); + + +INT BeceemNVMRead( + struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + UINT uiOffset, + UINT uiNumBytes); + +INT BeceemNVMWrite( + struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + UINT uiOffset, + UINT uiNumBytes, + bool bVerify); + + +INT BcmInitNVM(struct bcm_mini_adapter *Adapter); + +INT BcmUpdateSectorSize(struct bcm_mini_adapter *Adapter,UINT uiSectorSize); +bool IsSectionExistInFlash(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val section); + +INT BcmGetFlash2xSectionalBitMap(struct bcm_mini_adapter *Adapter, struct bcm_flash2x_bitmap *psFlash2xBitMap); + +INT BcmFlash2xBulkWrite( + struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + enum bcm_flash2x_section_val eFlashSectionVal, + UINT uiOffset, + UINT uiNumBytes, + UINT bVerify); + +INT BcmFlash2xBulkRead( + struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + enum bcm_flash2x_section_val eFlashSectionVal, + UINT uiOffsetWithinSectionVal, + UINT uiNumBytes); + +INT BcmGetSectionValStartOffset(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlashSectionVal); + +INT BcmSetActiveSection(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectVal); +INT BcmAllocFlashCSStructure(struct bcm_mini_adapter *psAdapter); +INT BcmDeAllocFlashCSStructure(struct bcm_mini_adapter *psAdapter); + +INT BcmCopyISO(struct bcm_mini_adapter *Adapter, struct bcm_flash2x_copy_section sCopySectStrut); +INT BcmFlash2xCorruptSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectionVal); +INT BcmFlash2xWriteSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlashSectionVal); +INT validateFlash2xReadWrite(struct bcm_mini_adapter *Adapter, struct bcm_flash2x_readwrite *psFlash2xReadWrite); +INT IsFlash2x(struct bcm_mini_adapter *Adapter); +INT BcmCopySection(struct bcm_mini_adapter *Adapter, + enum bcm_flash2x_section_val SrcSection, + enum bcm_flash2x_section_val DstSection, + UINT offset, + UINT numOfBytes); + + +bool IsNonCDLessDevice(struct bcm_mini_adapter *Adapter); + + +VOID OverrideServiceFlowParams(struct bcm_mini_adapter *Adapter,PUINT puiBuffer); + +int wrmaltWithLock (struct bcm_mini_adapter *Adapter, UINT uiAddress, unsigned int *pucBuff, size_t sSize); +int rdmaltWithLock (struct bcm_mini_adapter *Adapter, UINT uiAddress, unsigned int *pucBuff, size_t sSize); + +int wrmWithLock(struct bcm_mini_adapter *Adapter, UINT uiAddress, PCHAR pucBuff, size_t size); +INT buffDnldVerify(struct bcm_mini_adapter *Adapter, unsigned char *mappedbuffer, unsigned int u32FirmwareLength, + unsigned long u32StartingAddress); + + +VOID putUsbSuspend(struct work_struct *work); +bool IsReqGpioIsLedInNVM(struct bcm_mini_adapter *Adapter, UINT gpios); + + +#endif + + + + diff --git a/drivers/staging/bcm/Qos.c b/drivers/staging/bcm/Qos.c new file mode 100644 index 00000000000..0c742da8c6b --- /dev/null +++ b/drivers/staging/bcm/Qos.c @@ -0,0 +1,777 @@ +/** +@file Qos.C +This file contains the routines related to Quality of Service. +*/ +#include "headers.h" + +static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter, + PVOID pvEthPayload, + struct bcm_eth_packet_info *pstEthCsPktInfo); + +static bool EThCSClassifyPkt(struct bcm_mini_adapter *Adapter, + struct sk_buff *skb, + struct bcm_eth_packet_info *pstEthCsPktInfo, + struct bcm_classifier_rule *pstClassifierRule, + B_UINT8 EthCSCupport); + +static USHORT IpVersion4(struct bcm_mini_adapter *Adapter, struct iphdr *iphd, + struct bcm_classifier_rule *pstClassifierRule); + +static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex); + + +/******************************************************************* +* Function - MatchSrcIpAddress() +* +* Description - Checks whether the Source IP address from the packet +* matches with that of Queue. +* +* Parameters - pstClassifierRule: Pointer to the packet info structure. +* - ulSrcIP : Source IP address from the packet. +* +* Returns - TRUE(If address matches) else FAIL . +*********************************************************************/ +static bool MatchSrcIpAddress(struct bcm_classifier_rule *pstClassifierRule, ULONG ulSrcIP) +{ + UCHAR ucLoopIndex = 0; + + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + ulSrcIP = ntohl(ulSrcIP); + if (0 == pstClassifierRule->ucIPSourceAddressLength) + return TRUE; + for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPSourceAddressLength); ucLoopIndex++) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Mask:0x%x PacketIp:0x%x and Classification:0x%x", (UINT)pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)ulSrcIP, (UINT)pstClassifierRule->stSrcIpAddress.ulIpv6Addr[ucLoopIndex]); + if ((pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex] & ulSrcIP) == + (pstClassifierRule->stSrcIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stSrcIpAddress.ulIpv4Mask[ucLoopIndex])) + return TRUE; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Ip Address Not Matched"); + return false; +} + + +/******************************************************************* +* Function - MatchDestIpAddress() +* +* Description - Checks whether the Destination IP address from the packet +* matches with that of Queue. +* +* Parameters - pstClassifierRule: Pointer to the packet info structure. +* - ulDestIP : Destination IP address from the packet. +* +* Returns - TRUE(If address matches) else FAIL . +*********************************************************************/ +static bool MatchDestIpAddress(struct bcm_classifier_rule *pstClassifierRule, ULONG ulDestIP) +{ + UCHAR ucLoopIndex = 0; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + ulDestIP = ntohl(ulDestIP); + if (0 == pstClassifierRule->ucIPDestinationAddressLength) + return TRUE; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address 0x%x 0x%x 0x%x ", (UINT)ulDestIP, (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex], (UINT)pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex]); + + for (ucLoopIndex = 0; ucLoopIndex < (pstClassifierRule->ucIPDestinationAddressLength); ucLoopIndex++) { + if ((pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex] & ulDestIP) == + (pstClassifierRule->stDestIpAddress.ulIpv4Addr[ucLoopIndex] & pstClassifierRule->stDestIpAddress.ulIpv4Mask[ucLoopIndex])) + return TRUE; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Ip Address Not Matched"); + return false; +} + + +/************************************************************************ +* Function - MatchTos() +* +* Description - Checks the TOS from the packet matches with that of queue. +* +* Parameters - pstClassifierRule : Pointer to the packet info structure. +* - ucTypeOfService: TOS from the packet. +* +* Returns - TRUE(If address matches) else FAIL. +**************************************************************************/ +static bool MatchTos(struct bcm_classifier_rule *pstClassifierRule, UCHAR ucTypeOfService) +{ + + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + if (3 != pstClassifierRule->ucIPTypeOfServiceLength) + return TRUE; + + if (((pstClassifierRule->ucTosMask & ucTypeOfService) <= pstClassifierRule->ucTosHigh) && ((pstClassifierRule->ucTosMask & ucTypeOfService) >= pstClassifierRule->ucTosLow)) + return TRUE; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Type Of Service Not Matched"); + return false; +} + + +/*************************************************************************** +* Function - MatchProtocol() +* +* Description - Checks the protocol from the packet matches with that of queue. +* +* Parameters - pstClassifierRule: Pointer to the packet info structure. +* - ucProtocol : Protocol from the packet. +* +* Returns - TRUE(If address matches) else FAIL. +****************************************************************************/ +bool MatchProtocol(struct bcm_classifier_rule *pstClassifierRule, UCHAR ucProtocol) +{ + UCHAR ucLoopIndex = 0; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + if (0 == pstClassifierRule->ucProtocolLength) + return TRUE; + for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucProtocolLength; ucLoopIndex++) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol:0x%X Classification Protocol:0x%X", ucProtocol, pstClassifierRule->ucProtocol[ucLoopIndex]); + if (pstClassifierRule->ucProtocol[ucLoopIndex] == ucProtocol) + return TRUE; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Not Matched"); + return false; +} + + +/*********************************************************************** +* Function - MatchSrcPort() +* +* Description - Checks, Source port from the packet matches with that of queue. +* +* Parameters - pstClassifierRule: Pointer to the packet info structure. +* - ushSrcPort : Source port from the packet. +* +* Returns - TRUE(If address matches) else FAIL. +***************************************************************************/ +bool MatchSrcPort(struct bcm_classifier_rule *pstClassifierRule, USHORT ushSrcPort) +{ + UCHAR ucLoopIndex = 0; + + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + + if (0 == pstClassifierRule->ucSrcPortRangeLength) + return TRUE; + for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucSrcPortRangeLength; ucLoopIndex++) { + if (ushSrcPort <= pstClassifierRule->usSrcPortRangeHi[ucLoopIndex] && + ushSrcPort >= pstClassifierRule->usSrcPortRangeLo[ucLoopIndex]) + return TRUE; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port: %x Not Matched ", ushSrcPort); + return false; +} + + +/*********************************************************************** +* Function - MatchDestPort() +* +* Description - Checks, Destination port from packet matches with that of queue. +* +* Parameters - pstClassifierRule: Pointer to the packet info structure. +* - ushDestPort : Destination port from the packet. +* +* Returns - TRUE(If address matches) else FAIL. +***************************************************************************/ +bool MatchDestPort(struct bcm_classifier_rule *pstClassifierRule, USHORT ushDestPort) +{ + UCHAR ucLoopIndex = 0; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + if (0 == pstClassifierRule->ucDestPortRangeLength) + return TRUE; + + for (ucLoopIndex = 0; ucLoopIndex < pstClassifierRule->ucDestPortRangeLength; ucLoopIndex++) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Matching Port:0x%X 0x%X 0x%X", ushDestPort, pstClassifierRule->usDestPortRangeLo[ucLoopIndex], pstClassifierRule->usDestPortRangeHi[ucLoopIndex]); + + if (ushDestPort <= pstClassifierRule->usDestPortRangeHi[ucLoopIndex] && + ushDestPort >= pstClassifierRule->usDestPortRangeLo[ucLoopIndex]) + return TRUE; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dest Port: %x Not Matched", ushDestPort); + return false; +} +/** +@ingroup tx_functions +Compares IPV4 Ip address and port number +@return Queue Index. +*/ +static USHORT IpVersion4(struct bcm_mini_adapter *Adapter, + struct iphdr *iphd, + struct bcm_classifier_rule *pstClassifierRule) +{ + struct bcm_transport_header *xprt_hdr = NULL; + bool bClassificationSucceed = false; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "========>"); + + xprt_hdr = (struct bcm_transport_header *)((PUCHAR)iphd + sizeof(struct iphdr)); + + do { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Trying to see Direction = %d %d", + pstClassifierRule->ucDirection, + pstClassifierRule->usVCID_Value); + + //Checking classifier validity + if (!pstClassifierRule->bUsed || pstClassifierRule->ucDirection == DOWNLINK_DIR) + break; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "is IPv6 check!"); + if (pstClassifierRule->bIpv6Protocol) + break; + + //**************Checking IP header parameter**************************// + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Trying to match Source IP Address"); + if (!MatchSrcIpAddress(pstClassifierRule, iphd->saddr)) + break; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source IP Address Matched"); + + if (!MatchDestIpAddress(pstClassifierRule, iphd->daddr)) + break; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination IP Address Matched"); + + if (!MatchTos(pstClassifierRule, iphd->tos)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Match failed\n"); + break; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "TOS Matched"); + + if (!MatchProtocol(pstClassifierRule, iphd->protocol)) + break; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Protocol Matched"); + + //if protocol is not TCP or UDP then no need of comparing source port and destination port + if (iphd->protocol != TCP && iphd->protocol != UDP) { + bClassificationSucceed = TRUE; + break; + } + //******************Checking Transport Layer Header field if present *****************// + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Source Port %04x", + (iphd->protocol == UDP) ? xprt_hdr->uhdr.source : xprt_hdr->thdr.source); + + if (!MatchSrcPort(pstClassifierRule, + ntohs((iphd->protocol == UDP) ? + xprt_hdr->uhdr.source : xprt_hdr->thdr.source))) + break; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Src Port Matched"); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Destination Port %04x", + (iphd->protocol == UDP) ? xprt_hdr->uhdr.dest : + xprt_hdr->thdr.dest); + if (!MatchDestPort(pstClassifierRule, + ntohs((iphd->protocol == UDP) ? + xprt_hdr->uhdr.dest : xprt_hdr->thdr.dest))) + break; + bClassificationSucceed = TRUE; + } while (0); + + if (TRUE == bClassificationSucceed) { + INT iMatchedSFQueueIndex = 0; + iMatchedSFQueueIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID); + if (iMatchedSFQueueIndex >= NO_OF_QUEUES) + bClassificationSucceed = false; + else if (false == Adapter->PackInfo[iMatchedSFQueueIndex].bActive) + bClassificationSucceed = false; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "IpVersion4 <=========="); + + return bClassificationSucceed; +} + +VOID PruneQueueAllSF(struct bcm_mini_adapter *Adapter) +{ + UINT iIndex = 0; + + for (iIndex = 0; iIndex < HiPriority; iIndex++) { + if (!Adapter->PackInfo[iIndex].bValid) + continue; + + PruneQueue(Adapter, iIndex); + } +} + + +/** +@ingroup tx_functions +This function checks if the max queue size for a queue +is less than number of bytes in the queue. If so - +drops packets from the Head till the number of bytes is +less than or equal to max queue size for the queue. +*/ +static VOID PruneQueue(struct bcm_mini_adapter *Adapter, INT iIndex) +{ + struct sk_buff* PacketToDrop = NULL; + struct net_device_stats *netstats; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "=====> Index %d", iIndex); + + if (iIndex == HiPriority) + return; + + if (!Adapter || (iIndex < 0) || (iIndex > HiPriority)) + return; + + /* To Store the netdevice statistic */ + netstats = &Adapter->dev->stats; + + spin_lock_bh(&Adapter->PackInfo[iIndex].SFQueueLock); + + while (1) { +// while((UINT)Adapter->PackInfo[iIndex].uiCurrentPacketsOnHost > +// SF_MAX_ALLOWED_PACKETS_TO_BACKUP) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "uiCurrentBytesOnHost:%x uiMaxBucketSize :%x", + Adapter->PackInfo[iIndex].uiCurrentBytesOnHost, + Adapter->PackInfo[iIndex].uiMaxBucketSize); + + PacketToDrop = Adapter->PackInfo[iIndex].FirstTxQueue; + + if (PacketToDrop == NULL) + break; + if ((Adapter->PackInfo[iIndex].uiCurrentPacketsOnHost < SF_MAX_ALLOWED_PACKETS_TO_BACKUP) && + ((1000*(jiffies - *((B_UINT32 *)(PacketToDrop->cb)+SKB_CB_LATENCY_OFFSET))/HZ) <= Adapter->PackInfo[iIndex].uiMaxLatency)) + break; + + if (PacketToDrop) { + if (netif_msg_tx_err(Adapter)) + pr_info(PFX "%s: tx queue %d overlimit\n", + Adapter->dev->name, iIndex); + + netstats->tx_dropped++; + + DEQUEUEPACKET(Adapter->PackInfo[iIndex].FirstTxQueue, + Adapter->PackInfo[iIndex].LastTxQueue); + /// update current bytes and packets count + Adapter->PackInfo[iIndex].uiCurrentBytesOnHost -= + PacketToDrop->len; + Adapter->PackInfo[iIndex].uiCurrentPacketsOnHost--; + /// update dropped bytes and packets counts + Adapter->PackInfo[iIndex].uiDroppedCountBytes += PacketToDrop->len; + Adapter->PackInfo[iIndex].uiDroppedCountPackets++; + dev_kfree_skb(PacketToDrop); + + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "Dropped Bytes:%x Dropped Packets:%x", + Adapter->PackInfo[iIndex].uiDroppedCountBytes, + Adapter->PackInfo[iIndex].uiDroppedCountPackets); + + atomic_dec(&Adapter->TotalPacketCount); + } + + spin_unlock_bh(&Adapter->PackInfo[iIndex].SFQueueLock); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "TotalPacketCount:%x", + atomic_read(&Adapter->TotalPacketCount)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, PRUNE_QUEUE, DBG_LVL_ALL, "<====="); +} + +VOID flush_all_queues(struct bcm_mini_adapter *Adapter) +{ + INT iQIndex; + UINT uiTotalPacketLength; + struct sk_buff* PacketToDrop = NULL; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "=====>"); + +// down(&Adapter->data_packet_queue_lock); + for (iQIndex = LowPriority; iQIndex < HiPriority; iQIndex++) { + struct net_device_stats *netstats = &Adapter->dev->stats; + + spin_lock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock); + while (Adapter->PackInfo[iQIndex].FirstTxQueue) { + PacketToDrop = Adapter->PackInfo[iQIndex].FirstTxQueue; + if (PacketToDrop) { + uiTotalPacketLength = PacketToDrop->len; + netstats->tx_dropped++; + } else + uiTotalPacketLength = 0; + + DEQUEUEPACKET(Adapter->PackInfo[iQIndex].FirstTxQueue, + Adapter->PackInfo[iQIndex].LastTxQueue); + + /* Free the skb */ + dev_kfree_skb(PacketToDrop); + + /// update current bytes and packets count + Adapter->PackInfo[iQIndex].uiCurrentBytesOnHost -= uiTotalPacketLength; + Adapter->PackInfo[iQIndex].uiCurrentPacketsOnHost--; + + /// update dropped bytes and packets counts + Adapter->PackInfo[iQIndex].uiDroppedCountBytes += uiTotalPacketLength; + Adapter->PackInfo[iQIndex].uiDroppedCountPackets++; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "Dropped Bytes:%x Dropped Packets:%x", + Adapter->PackInfo[iQIndex].uiDroppedCountBytes, + Adapter->PackInfo[iQIndex].uiDroppedCountPackets); + atomic_dec(&Adapter->TotalPacketCount); + } + spin_unlock_bh(&Adapter->PackInfo[iQIndex].SFQueueLock); + } +// up(&Adapter->data_packet_queue_lock); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "<====="); +} + +USHORT ClassifyPacket(struct bcm_mini_adapter *Adapter, struct sk_buff* skb) +{ + INT uiLoopIndex = 0; + struct bcm_classifier_rule *pstClassifierRule = NULL; + struct bcm_eth_packet_info stEthCsPktInfo; + PVOID pvEThPayload = NULL; + struct iphdr *pIpHeader = NULL; + INT uiSfIndex = 0; + USHORT usIndex = Adapter->usBestEffortQueueIndex; + bool bFragmentedPkt = false, bClassificationSucceed = false; + USHORT usCurrFragment = 0; + + struct bcm_tcp_header *pTcpHeader; + UCHAR IpHeaderLength; + UCHAR TcpHeaderLength; + + pvEThPayload = skb->data; + *((UINT32*) (skb->cb) +SKB_CB_TCPACK_OFFSET) = 0; + EThCSGetPktInfo(Adapter, pvEThPayload, &stEthCsPktInfo); + + switch (stEthCsPktInfo.eNwpktEthFrameType) { + case eEth802LLCFrame: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : 802LLCFrame\n"); + pIpHeader = pvEThPayload + sizeof(struct bcm_eth_llc_frame); + break; + case eEth802LLCSNAPFrame: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : 802LLC SNAP Frame\n"); + pIpHeader = pvEThPayload + sizeof(struct bcm_eth_llc_snap_frame); + break; + case eEth802QVLANFrame: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : 802.1Q VLANFrame\n"); + pIpHeader = pvEThPayload + sizeof(struct bcm_eth_q_frame); + break; + case eEthOtherFrame: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : ETH Other Frame\n"); + pIpHeader = pvEThPayload + sizeof(struct bcm_ethernet2_frame); + break; + default: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : Unrecognized ETH Frame\n"); + pIpHeader = pvEThPayload + sizeof(struct bcm_ethernet2_frame); + break; + } + + if (stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet) { + usCurrFragment = (ntohs(pIpHeader->frag_off) & IP_OFFSET); + if ((ntohs(pIpHeader->frag_off) & IP_MF) || usCurrFragment) + bFragmentedPkt = TRUE; + + if (bFragmentedPkt) { + //Fragmented Packet. Get Frag Classifier Entry. + pstClassifierRule = GetFragIPClsEntry(Adapter, pIpHeader->id, pIpHeader->saddr); + if (pstClassifierRule) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "It is next Fragmented pkt"); + bClassificationSucceed = TRUE; + } + if (!(ntohs(pIpHeader->frag_off) & IP_MF)) { + //Fragmented Last packet . Remove Frag Classifier Entry + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "This is the last fragmented Pkt"); + DelFragIPClsEntry(Adapter, pIpHeader->id, pIpHeader->saddr); + } + } + } + + for (uiLoopIndex = MAX_CLASSIFIERS - 1; uiLoopIndex >= 0; uiLoopIndex--) { + if (bClassificationSucceed) + break; + //Iterate through all classifiers which are already in order of priority + //to classify the packet until match found + do { + if (false == Adapter->astClassifierTable[uiLoopIndex].bUsed) { + bClassificationSucceed = false; + break; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Adapter->PackInfo[%d].bvalid=True\n", uiLoopIndex); + + if (0 == Adapter->astClassifierTable[uiLoopIndex].ucDirection) { + bClassificationSucceed = false;//cannot be processed for classification. + break; // it is a down link connection + } + + pstClassifierRule = &Adapter->astClassifierTable[uiLoopIndex]; + + uiSfIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID); + if (uiSfIndex >= NO_OF_QUEUES) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Queue Not Valid. SearchSfid for this classifier Failed\n"); + break; + } + + if (Adapter->PackInfo[uiSfIndex].bEthCSSupport) { + + if (eEthUnsupportedFrame == stEthCsPktInfo.eNwpktEthFrameType) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet Not a Valid Supported Ethernet Frame\n"); + bClassificationSucceed = false; + break; + } + + + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Performing ETH CS Classification on Classifier Rule ID : %x Service Flow ID : %lx\n", pstClassifierRule->uiClassifierRuleIndex, Adapter->PackInfo[uiSfIndex].ulSFID); + bClassificationSucceed = EThCSClassifyPkt(Adapter, skb, &stEthCsPktInfo, pstClassifierRule, Adapter->PackInfo[uiSfIndex].bEthCSSupport); + + if (!bClassificationSucceed) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ClassifyPacket : Ethernet CS Classification Failed\n"); + break; + } + } else { // No ETH Supported on this SF + if (eEthOtherFrame != stEthCsPktInfo.eNwpktEthFrameType) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet Not a 802.3 Ethernet Frame... hence not allowed over non-ETH CS SF\n"); + bClassificationSucceed = false; + break; + } + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Proceeding to IP CS Clasification"); + + if (Adapter->PackInfo[uiSfIndex].bIPCSSupport) { + + if (stEthCsPktInfo.eNwpktIPFrameType == eNonIPPacket) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, " ClassifyPacket : Packet is Not an IP Packet\n"); + bClassificationSucceed = false; + break; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "Dump IP Header :\n"); + DumpFullPacket((PUCHAR)pIpHeader, 20); + + if (stEthCsPktInfo.eNwpktIPFrameType == eIPv4Packet) + bClassificationSucceed = IpVersion4(Adapter, pIpHeader, pstClassifierRule); + else if (stEthCsPktInfo.eNwpktIPFrameType == eIPv6Packet) + bClassificationSucceed = IpVersion6(Adapter, pIpHeader, pstClassifierRule); + } + + } while (0); + } + + if (bClassificationSucceed == TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "CF id : %d, SF ID is =%lu", pstClassifierRule->uiClassifierRuleIndex, pstClassifierRule->ulSFID); + + //Store The matched Classifier in SKB + *((UINT32*)(skb->cb)+SKB_CB_CLASSIFICATION_OFFSET) = pstClassifierRule->uiClassifierRuleIndex; + if ((TCP == pIpHeader->protocol) && !bFragmentedPkt && (ETH_AND_IP_HEADER_LEN + TCP_HEADER_LEN <= skb->len)) { + IpHeaderLength = pIpHeader->ihl; + pTcpHeader = (struct bcm_tcp_header *)(((PUCHAR)pIpHeader)+(IpHeaderLength*4)); + TcpHeaderLength = GET_TCP_HEADER_LEN(pTcpHeader->HeaderLength); + + if ((pTcpHeader->ucFlags & TCP_ACK) && + (ntohs(pIpHeader->tot_len) == (IpHeaderLength*4)+(TcpHeaderLength*4))) + *((UINT32*) (skb->cb) + SKB_CB_TCPACK_OFFSET) = TCP_ACK; + } + + usIndex = SearchSfid(Adapter, pstClassifierRule->ulSFID); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "index is =%d", usIndex); + + //If this is the first fragment of a Fragmented pkt, add this CF. Only This CF should be used for all other fragment of this Pkt. + if (bFragmentedPkt && (usCurrFragment == 0)) { + //First Fragment of Fragmented Packet. Create Frag CLS Entry + struct bcm_fragmented_packet_info stFragPktInfo; + stFragPktInfo.bUsed = TRUE; + stFragPktInfo.ulSrcIpAddress = pIpHeader->saddr; + stFragPktInfo.usIpIdentification = pIpHeader->id; + stFragPktInfo.pstMatchedClassifierEntry = pstClassifierRule; + stFragPktInfo.bOutOfOrderFragment = false; + AddFragIPClsEntry(Adapter, &stFragPktInfo); + } + + + } + + if (bClassificationSucceed) + return usIndex; + else + return INVALID_QUEUE_INDEX; +} + +static bool EthCSMatchSrcMACAddress(struct bcm_classifier_rule *pstClassifierRule, PUCHAR Mac) +{ + UINT i = 0; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + if (pstClassifierRule->ucEthCSSrcMACLen == 0) + return TRUE; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s\n", __func__); + for (i = 0; i < MAC_ADDRESS_SIZE; i++) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n", i, Mac[i], pstClassifierRule->au8EThCSSrcMAC[i], pstClassifierRule->au8EThCSSrcMACMask[i]); + if ((pstClassifierRule->au8EThCSSrcMAC[i] & pstClassifierRule->au8EThCSSrcMACMask[i]) != + (Mac[i] & pstClassifierRule->au8EThCSSrcMACMask[i])) + return false; + } + return TRUE; +} + +static bool EthCSMatchDestMACAddress(struct bcm_classifier_rule *pstClassifierRule, PUCHAR Mac) +{ + UINT i = 0; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + if (pstClassifierRule->ucEthCSDestMACLen == 0) + return TRUE; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s\n", __func__); + for (i = 0; i < MAC_ADDRESS_SIZE; i++) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "SRC MAC[%x] = %x ClassifierRuleSrcMAC = %x Mask : %x\n", i, Mac[i], pstClassifierRule->au8EThCSDestMAC[i], pstClassifierRule->au8EThCSDestMACMask[i]); + if ((pstClassifierRule->au8EThCSDestMAC[i] & pstClassifierRule->au8EThCSDestMACMask[i]) != + (Mac[i] & pstClassifierRule->au8EThCSDestMACMask[i])) + return false; + } + return TRUE; +} + +static bool EthCSMatchEThTypeSAP(struct bcm_classifier_rule *pstClassifierRule, struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + if ((pstClassifierRule->ucEtherTypeLen == 0) || + (pstClassifierRule->au8EthCSEtherType[0] == 0)) + return TRUE; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s SrcEtherType:%x CLS EtherType[0]:%x\n", __func__, pstEthCsPktInfo->usEtherType, pstClassifierRule->au8EthCSEtherType[0]); + if (pstClassifierRule->au8EthCSEtherType[0] == 1) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s CLS EtherType[1]:%x EtherType[2]:%x\n", __func__, pstClassifierRule->au8EthCSEtherType[1], pstClassifierRule->au8EthCSEtherType[2]); + + if (memcmp(&pstEthCsPktInfo->usEtherType, &pstClassifierRule->au8EthCSEtherType[1], 2) == 0) + return TRUE; + else + return false; + } + + if (pstClassifierRule->au8EthCSEtherType[0] == 2) { + if (eEth802LLCFrame != pstEthCsPktInfo->eNwpktEthFrameType) + return false; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s EthCS DSAP:%x EtherType[2]:%x\n", __func__, pstEthCsPktInfo->ucDSAP, pstClassifierRule->au8EthCSEtherType[2]); + if (pstEthCsPktInfo->ucDSAP == pstClassifierRule->au8EthCSEtherType[2]) + return TRUE; + else + return false; + + } + + return false; + +} + +static bool EthCSMatchVLANRules(struct bcm_classifier_rule *pstClassifierRule, struct sk_buff* skb, struct bcm_eth_packet_info *pstEthCsPktInfo) +{ + bool bClassificationSucceed = false; + USHORT usVLANID; + B_UINT8 uPriority = 0; + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s CLS UserPrio:%x CLS VLANID:%x\n", __func__, ntohs(*((USHORT *)pstClassifierRule->usUserPriority)), pstClassifierRule->usVLANID); + + /* In case FW didn't receive the TLV, the priority field should be ignored */ + if (pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_USER_PRIORITY_VALID)) { + if (pstEthCsPktInfo->eNwpktEthFrameType != eEth802QVLANFrame) + return false; + + uPriority = (ntohs(*(USHORT *)(skb->data + sizeof(struct bcm_eth_header))) & 0xF000) >> 13; + + if ((uPriority >= pstClassifierRule->usUserPriority[0]) && (uPriority <= pstClassifierRule->usUserPriority[1])) + bClassificationSucceed = TRUE; + + if (!bClassificationSucceed) + return false; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ETH CS 802.1 D User Priority Rule Matched\n"); + + bClassificationSucceed = false; + + if (pstClassifierRule->usValidityBitMap & (1<<PKT_CLASSIFICATION_VLANID_VALID)) { + if (pstEthCsPktInfo->eNwpktEthFrameType != eEth802QVLANFrame) + return false; + + usVLANID = ntohs(*(USHORT *)(skb->data + sizeof(struct bcm_eth_header))) & 0xFFF; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "%s Pkt VLANID %x Priority: %d\n", __func__, usVLANID, uPriority); + + if (usVLANID == ((pstClassifierRule->usVLANID & 0xFFF0) >> 4)) + bClassificationSucceed = TRUE; + + if (!bClassificationSucceed) + return false; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ETH CS 802.1 Q VLAN ID Rule Matched\n"); + + return TRUE; +} + + +static bool EThCSClassifyPkt(struct bcm_mini_adapter *Adapter, struct sk_buff* skb, + struct bcm_eth_packet_info *pstEthCsPktInfo, + struct bcm_classifier_rule *pstClassifierRule, + B_UINT8 EthCSCupport) +{ + bool bClassificationSucceed = false; + bClassificationSucceed = EthCSMatchSrcMACAddress(pstClassifierRule, ((struct bcm_eth_header *)(skb->data))->au8SourceAddress); + if (!bClassificationSucceed) + return false; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ETH CS SrcMAC Matched\n"); + + bClassificationSucceed = EthCSMatchDestMACAddress(pstClassifierRule, ((struct bcm_eth_header *)(skb->data))->au8DestinationAddress); + if (!bClassificationSucceed) + return false; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ETH CS DestMAC Matched\n"); + + //classify on ETHType/802.2SAP TLV + bClassificationSucceed = EthCSMatchEThTypeSAP(pstClassifierRule, skb, pstEthCsPktInfo); + if (!bClassificationSucceed) + return false; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ETH CS EthType/802.2SAP Matched\n"); + + //classify on 802.1VLAN Header Parameters + + bClassificationSucceed = EthCSMatchVLANRules(pstClassifierRule, skb, pstEthCsPktInfo); + if (!bClassificationSucceed) + return false; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "ETH CS 802.1 VLAN Rules Matched\n"); + + return bClassificationSucceed; +} + +static void EThCSGetPktInfo(struct bcm_mini_adapter *Adapter, PVOID pvEthPayload, + struct bcm_eth_packet_info *pstEthCsPktInfo) +{ + USHORT u16Etype = ntohs(((struct bcm_eth_header *)pvEthPayload)->u16Etype); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCSGetPktInfo : Eth Hdr Type : %X\n", u16Etype); + if (u16Etype > 0x5dc) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCSGetPktInfo : ETH2 Frame\n"); + //ETH2 Frame + if (u16Etype == ETHERNET_FRAMETYPE_802QVLAN) { + //802.1Q VLAN Header + pstEthCsPktInfo->eNwpktEthFrameType = eEth802QVLANFrame; + u16Etype = ((struct bcm_eth_q_frame *)pvEthPayload)->EthType; + //((ETH_CS_802_Q_FRAME*)pvEthPayload)->UserPriority + } else { + pstEthCsPktInfo->eNwpktEthFrameType = eEthOtherFrame; + u16Etype = ntohs(u16Etype); + } + } else { + //802.2 LLC + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "802.2 LLC Frame\n"); + pstEthCsPktInfo->eNwpktEthFrameType = eEth802LLCFrame; + pstEthCsPktInfo->ucDSAP = ((struct bcm_eth_llc_frame *)pvEthPayload)->DSAP; + if (pstEthCsPktInfo->ucDSAP == 0xAA && ((struct bcm_eth_llc_frame *)pvEthPayload)->SSAP == 0xAA) { + //SNAP Frame + pstEthCsPktInfo->eNwpktEthFrameType = eEth802LLCSNAPFrame; + u16Etype = ((struct bcm_eth_llc_snap_frame *)pvEthPayload)->usEtherType; + } + } + if (u16Etype == ETHERNET_FRAMETYPE_IPV4) + pstEthCsPktInfo->eNwpktIPFrameType = eIPv4Packet; + else if (u16Etype == ETHERNET_FRAMETYPE_IPV6) + pstEthCsPktInfo->eNwpktIPFrameType = eIPv6Packet; + else + pstEthCsPktInfo->eNwpktIPFrameType = eNonIPPacket; + + pstEthCsPktInfo->usEtherType = ((struct bcm_eth_header *)pvEthPayload)->u16Etype; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCsPktInfo->eNwpktIPFrameType : %x\n", pstEthCsPktInfo->eNwpktIPFrameType); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCsPktInfo->eNwpktEthFrameType : %x\n", pstEthCsPktInfo->eNwpktEthFrameType); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, IPV4_DBG, DBG_LVL_ALL, "EthCsPktInfo->usEtherType : %x\n", pstEthCsPktInfo->usEtherType); +} + + + diff --git a/drivers/staging/bcm/Queue.h b/drivers/staging/bcm/Queue.h new file mode 100644 index 00000000000..e1f1da2bb6d --- /dev/null +++ b/drivers/staging/bcm/Queue.h @@ -0,0 +1,31 @@ +/************************************* +* Queue.h +**************************************/ +#ifndef __QUEUE_H__ +#define __QUEUE_H__ + + + +#define ENQUEUEPACKET(_Head, _Tail,_Packet) \ +do \ +{ \ + if (!_Head) { \ + _Head = _Packet; \ + } \ + else { \ + (_Tail)->next = _Packet; \ + } \ + (_Packet)->next = NULL; \ + _Tail = _Packet; \ +}while(0) +#define DEQUEUEPACKET(Head, Tail ) \ +do \ +{ if(Head) \ + { \ + if (!Head->next) { \ + Tail = NULL; \ + } \ + Head = Head->next; \ + } \ +}while(0) +#endif //__QUEUE_H__ diff --git a/drivers/staging/bcm/TODO b/drivers/staging/bcm/TODO new file mode 100644 index 00000000000..cd3e9f2ed87 --- /dev/null +++ b/drivers/staging/bcm/TODO @@ -0,0 +1,22 @@ +This driver is barely functional in its current state. + +BIG: + - existing API is (/dev/tarang) should be replaced + Is it possible to use same API as Intel Wimax stack and + have same user level components. + - Qos and queue model is non-standard and inflexible. + Use existing TC Qos? + +TODO: + - support more than one board - eliminate global variables + - remove developer debug BCM_DEBUG() macros + add a limited number of messages through netif_msg() + - fix non-standard kernel style + - checkpatch warnings + - use request firmware + - fix use of file I/O to load config with better API + - merge some files together? + - cleanup/eliminate debug messages + + + diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c new file mode 100644 index 00000000000..49767468ac2 --- /dev/null +++ b/drivers/staging/bcm/Transmit.c @@ -0,0 +1,245 @@ +/** + * @file Transmit.c + * @defgroup tx_functions Transmission + * @section Queueing + * @dot + * digraph transmit1 { + * node[shape=box] + * edge[weight=5;color=red] + * + * bcm_transmit->GetPacketQueueIndex[label="IP Packet"] + * GetPacketQueueIndex->IpVersion4[label="IPV4"] + * GetPacketQueueIndex->IpVersion6[label="IPV6"] + * } + * + * @enddot + * + * @section De-Queueing + * @dot + * digraph transmit2 { + * node[shape=box] + * edge[weight=5;color=red] + * interrupt_service_thread->transmit_packets + * tx_pkt_hdler->transmit_packets + * transmit_packets->CheckAndSendPacketFromIndex + * transmit_packets->UpdateTokenCount + * CheckAndSendPacketFromIndex->PruneQueue + * CheckAndSendPacketFromIndex->IsPacketAllowedForFlow + * CheckAndSendPacketFromIndex->SendControlPacket[label="control pkt"] + * SendControlPacket->bcm_cmd53 + * CheckAndSendPacketFromIndex->SendPacketFromQueue[label="data pkt"] + * SendPacketFromQueue->SetupNextSend->bcm_cmd53 + * } + * @enddot + */ + +#include "headers.h" + +/** + * @ingroup ctrl_pkt_functions + * This function dispatches control packet to the h/w interface + * @return zero(success) or -ve value(failure) + */ +int SendControlPacket(struct bcm_mini_adapter *Adapter, char *pControlPacket) +{ + struct bcm_leader *PLeader = (struct bcm_leader *)pControlPacket; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Tx"); + if (!pControlPacket || !Adapter) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, + "Got NULL Control Packet or Adapter"); + return STATUS_FAILURE; + } + if ((atomic_read(&Adapter->CurrNumFreeTxDesc) < + ((PLeader->PLength-1)/MAX_DEVICE_DESC_SIZE)+1)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, + "NO FREE DESCRIPTORS TO SEND CONTROL PACKET"); + return STATUS_FAILURE; + } + + /* Update the netdevice statistics */ + /* Dump Packet */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Status: %x", PLeader->Status); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader VCID: %x", PLeader->Vcid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Length: %x", PLeader->PLength); + if (Adapter->device_removed) + return 0; + + if (netif_msg_pktdata(Adapter)) + print_hex_dump(KERN_DEBUG, PFX "tx control: ", DUMP_PREFIX_NONE, + 16, 1, pControlPacket, PLeader->PLength + LEADER_SIZE, 0); + + Adapter->interface_transmit(Adapter->pvInterfaceAdapter, + pControlPacket, (PLeader->PLength + LEADER_SIZE)); + + atomic_dec(&Adapter->CurrNumFreeTxDesc); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<========="); + return STATUS_SUCCESS; +} + +/** + * @ingroup tx_functions + * This function despatches the IP packets with the given vcid + * to the target via the host h/w interface. + * @return zero(success) or -ve value(failure) + */ +int SetupNextSend(struct bcm_mini_adapter *Adapter, struct sk_buff *Packet, USHORT Vcid) +{ + int status = 0; + bool bHeaderSupressionEnabled = false; + B_UINT16 uiClassifierRuleID; + u16 QueueIndex = skb_get_queue_mapping(Packet); + struct bcm_leader Leader = {0}; + + if (Packet->len > MAX_DEVICE_DESC_SIZE) { + status = STATUS_FAILURE; + goto errExit; + } + + /* Get the Classifier Rule ID */ + uiClassifierRuleID = *((UINT32 *) (Packet->cb) + SKB_CB_CLASSIFICATION_OFFSET); + + bHeaderSupressionEnabled = Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled + & Adapter->bPHSEnabled; + + if (Adapter->device_removed) { + status = STATUS_FAILURE; + goto errExit; + } + + status = PHSTransmit(Adapter, &Packet, Vcid, uiClassifierRuleID, bHeaderSupressionEnabled, + (UINT *)&Packet->len, Adapter->PackInfo[QueueIndex].bEthCSSupport); + + if (status != STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, + "PHS Transmit failed..\n"); + goto errExit; + } + + Leader.Vcid = Vcid; + + if (TCP_ACK == *((UINT32 *) (Packet->cb) + SKB_CB_TCPACK_OFFSET)) + Leader.Status = LEADER_STATUS_TCP_ACK; + else + Leader.Status = LEADER_STATUS; + + if (Adapter->PackInfo[QueueIndex].bEthCSSupport) { + Leader.PLength = Packet->len; + if (skb_headroom(Packet) < LEADER_SIZE) { + status = skb_cow(Packet, LEADER_SIZE); + if (status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "bcm_transmit : Failed To Increase headRoom\n"); + goto errExit; + } + } + skb_push(Packet, LEADER_SIZE); + memcpy(Packet->data, &Leader, LEADER_SIZE); + } else { + Leader.PLength = Packet->len - ETH_HLEN; + memcpy((struct bcm_leader *)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE); + } + + status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter, + Packet->data, (Leader.PLength + LEADER_SIZE)); + if (status) { + ++Adapter->dev->stats.tx_errors; + if (netif_msg_tx_err(Adapter)) + pr_info(PFX "%s: transmit error %d\n", Adapter->dev->name, + status); + } else { + struct net_device_stats *netstats = &Adapter->dev->stats; + Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength; + + netstats->tx_bytes += Leader.PLength; + ++netstats->tx_packets; + + Adapter->PackInfo[QueueIndex].uiCurrentTokenCount -= Leader.PLength << 3; + Adapter->PackInfo[QueueIndex].uiSentBytes += (Packet->len); + Adapter->PackInfo[QueueIndex].uiSentPackets++; + Adapter->PackInfo[QueueIndex].NumOfPacketsSent++; + + atomic_dec(&Adapter->PackInfo[QueueIndex].uiPerSFTxResourceCount); + Adapter->PackInfo[QueueIndex].uiThisPeriodSentBytes += Leader.PLength; + } + + atomic_dec(&Adapter->CurrNumFreeTxDesc); + +errExit: + dev_kfree_skb(Packet); + return status; +} + +static int tx_pending(struct bcm_mini_adapter *Adapter) +{ + return (atomic_read(&Adapter->TxPktAvail) + && MINIMUM_PENDING_DESCRIPTORS < atomic_read(&Adapter->CurrNumFreeTxDesc)) + || Adapter->device_removed || (1 == Adapter->downloadDDR); +} + +/** + * @ingroup tx_functions + * Transmit thread + */ +int tx_pkt_handler(struct bcm_mini_adapter *Adapter /**< pointer to adapter object*/) +{ + int status = 0; + + while (!kthread_should_stop()) { + /* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */ + if (Adapter->LinkUpStatus) + wait_event_timeout(Adapter->tx_packet_wait_queue, + tx_pending(Adapter), msecs_to_jiffies(10)); + else + wait_event_interruptible(Adapter->tx_packet_wait_queue, + tx_pending(Adapter)); + + if (Adapter->device_removed) + break; + + if (Adapter->downloadDDR == 1) { + Adapter->downloadDDR += 1; + status = download_ddr_settings(Adapter); + if (status) + pr_err(PFX "DDR DOWNLOAD FAILED! %d\n", status); + continue; + } + + /* Check end point for halt/stall. */ + if (Adapter->bEndPointHalted == TRUE) { + Bcm_clear_halt_of_endpoints(Adapter); + Adapter->bEndPointHalted = false; + StartInterruptUrb((struct bcm_interface_adapter *)(Adapter->pvInterfaceAdapter)); + } + + if (Adapter->LinkUpStatus && !Adapter->IdleMode) { + if (atomic_read(&Adapter->TotalPacketCount)) + update_per_sf_desc_cnts(Adapter); + } + + if (atomic_read(&Adapter->CurrNumFreeTxDesc) && + Adapter->LinkStatus == SYNC_UP_REQUEST && + !Adapter->bSyncUpRequestSent) { + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, + DBG_LVL_ALL, "Calling LinkMessage"); + LinkMessage(Adapter); + } + + if ((Adapter->IdleMode || Adapter->bShutStatus) && atomic_read(&Adapter->TotalPacketCount)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, + TX_PACKETS, DBG_LVL_ALL, + "Device in Low Power mode...waking up"); + Adapter->usIdleModePattern = ABORT_IDLE_MODE; + Adapter->bWakeUpDevice = TRUE; + wake_up(&Adapter->process_rx_cntrlpkt); + } + + transmit_packets(Adapter); + atomic_set(&Adapter->TxPktAvail, 0); + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, + "Exiting the tx thread..\n"); + Adapter->transmit_packet_thread = NULL; + return 0; +} diff --git a/drivers/staging/bcm/Typedefs.h b/drivers/staging/bcm/Typedefs.h new file mode 100644 index 00000000000..90b3b25dd60 --- /dev/null +++ b/drivers/staging/bcm/Typedefs.h @@ -0,0 +1,47 @@ +/**************************** +* Typedefs.h +****************************/ +#ifndef __TYPEDEFS_H__ +#define __TYPEDEFS_H__ +#define STATUS_SUCCESS 0 +#define STATUS_FAILURE -1 + + +#define TRUE 1 + + +typedef char CHAR; +typedef int INT; +typedef short SHORT; +typedef long LONG; +typedef void VOID; + +typedef unsigned char UCHAR; +typedef unsigned char B_UINT8; +typedef unsigned short USHORT; +typedef unsigned short B_UINT16; +typedef unsigned int UINT; +typedef unsigned int B_UINT32; +typedef unsigned long ULONG; +typedef unsigned long DWORD; + +typedef char *PCHAR; +typedef short *PSHORT; +typedef int *PINT; +typedef long *PLONG; +typedef void *PVOID; + +typedef unsigned char *PUCHAR; +typedef unsigned short *PUSHORT; +typedef unsigned int *PUINT; +typedef unsigned long *PULONG; +typedef unsigned long long ULONG64; +typedef unsigned long long LARGE_INTEGER; +typedef unsigned int UINT32; +#ifndef NULL +#define NULL 0 +#endif + + +#endif /* __TYPEDEFS_H__ */ + diff --git a/drivers/staging/bcm/cntrl_SignalingInterface.h b/drivers/staging/bcm/cntrl_SignalingInterface.h new file mode 100644 index 00000000000..8683c2d4276 --- /dev/null +++ b/drivers/staging/bcm/cntrl_SignalingInterface.h @@ -0,0 +1,311 @@ +#ifndef CNTRL_SIGNALING_INTERFACE_ +#define CNTRL_SIGNALING_INTERFACE_ + +#define DSA_REQ 11 +#define DSA_RSP 12 +#define DSA_ACK 13 +#define DSC_REQ 14 +#define DSC_RSP 15 +#define DSC_ACK 16 +#define DSD_REQ 17 +#define DSD_RSP 18 +#define DSD_ACK 19 +#define MAX_CLASSIFIERS_IN_SF 4 + +#define MAX_STRING_LEN 20 +#define MAX_PHS_LENGTHS 255 +#define VENDOR_PHS_PARAM_LENGTH 10 +#define MAX_NUM_ACTIVE_BS 10 +#define AUTH_TOKEN_LENGTH 10 +#define NUM_HARQ_CHANNELS 16 /* Changed from 10 to 16 to accommodate all HARQ channels */ +#define VENDOR_CLASSIFIER_PARAM_LENGTH 1 /* Changed the size to 1 byte since we dnt use it */ +#define VENDOR_SPECIF_QOS_PARAM 1 +#define VENDOR_PHS_PARAM_LENGTH 10 +#define MBS_CONTENTS_ID_LENGTH 10 +#define GLOBAL_SF_CLASSNAME_LENGTH 6 + +#define TYPE_OF_SERVICE_LENGTH 3 +#define IP_MASKED_SRC_ADDRESS_LENGTH 32 +#define IP_MASKED_DEST_ADDRESS_LENGTH 32 +#define PROTOCOL_SRC_PORT_RANGE_LENGTH 4 +#define PROTOCOL_DEST_PORT_RANGE_LENGTH 4 +#define ETHERNET_DEST_MAC_ADDR_LENGTH 12 +#define ETHERNET_SRC_MAC_ADDR_LENGTH 12 +#define NUM_ETHERTYPE_BYTES 3 +#define NUM_IPV6_FLOWLABLE_BYTES 3 + +struct bcm_packet_class_rules { + /* 16bit UserPriority Of The Service Flow */ + u16 u16UserPriority; + /* 16bit VLANID Of The Service Flow */ + u16 u16VLANID; + /* 16bit Packet Classification RuleIndex Of The Service Flow */ + u16 u16PacketClassificationRuleIndex; + /* 8bit Classifier Rule Priority Of The Service Flow */ + u8 u8ClassifierRulePriority; + /* Length of IP TypeOfService field */ + u8 u8IPTypeOfServiceLength; + /* 3bytes IP TypeOfService */ + u8 u8IPTypeOfService[TYPE_OF_SERVICE_LENGTH]; + /* Protocol used in classification of Service Flow */ + u8 u8Protocol; + /* Length of IP Masked Source Address */ + u8 u8IPMaskedSourceAddressLength; + /* IP Masked Source Address used in classification for the Service Flow */ + u8 u8IPMaskedSourceAddress[IP_MASKED_SRC_ADDRESS_LENGTH]; + /* Length of IP Destination Address */ + u8 u8IPDestinationAddressLength; + /* IP Destination Address used in classification for the Service Flow */ + u8 u8IPDestinationAddress[IP_MASKED_DEST_ADDRESS_LENGTH]; + /* Length of Protocol Source Port Range */ + u8 u8ProtocolSourcePortRangeLength; + /* Protocol Source Port Range used in the Service Flow */ + u8 u8ProtocolSourcePortRange[PROTOCOL_SRC_PORT_RANGE_LENGTH]; + /* Length of Protocol Dest Port Range */ + u8 u8ProtocolDestPortRangeLength; + /* Protocol Dest Port Range used in the Service Flow */ + u8 u8ProtocolDestPortRange[PROTOCOL_DEST_PORT_RANGE_LENGTH]; + /* Length of Ethernet Destination MAC Address */ + u8 u8EthernetDestMacAddressLength; + /* Ethernet Destination MAC Address used in classification of the Service Flow */ + u8 u8EthernetDestMacAddress[ETHERNET_DEST_MAC_ADDR_LENGTH]; + /* Length of Ethernet Source MAC Address */ + u8 u8EthernetSourceMACAddressLength; + /* Ethernet Source MAC Address used in classification of the Service Flow */ + u8 u8EthernetSourceMACAddress[ETHERNET_SRC_MAC_ADDR_LENGTH]; + /* Length of Ethertype */ + u8 u8EthertypeLength; + /* 3bytes Ethertype Of The Service Flow */ + u8 u8Ethertype[NUM_ETHERTYPE_BYTES]; + /* 8bit Associated PHSI Of The Service Flow */ + u8 u8AssociatedPHSI; + /* Length of Vendor Specific Classifier Param length Of The Service Flow */ + u8 u8VendorSpecificClassifierParamLength; + /* Vendor Specific Classifier Param Of The Service Flow */ + u8 u8VendorSpecificClassifierParam[VENDOR_CLASSIFIER_PARAM_LENGTH]; + /* Length Of IPv6 Flow Lable of the Service Flow */ + u8 u8IPv6FlowLableLength; + /* IPv6 Flow Lable Of The Service Flow */ + u8 u8IPv6FlowLable[NUM_IPV6_FLOWLABLE_BYTES]; + /* Action associated with the classifier rule */ + u8 u8ClassifierActionRule; + u16 u16ValidityBitMap; +}; + +struct bcm_phs_rules { + /* 8bit PHS Index Of The Service Flow */ + u8 u8PHSI; + /* PHSF Length Of The Service Flow */ + u8 u8PHSFLength; + /* String of bytes containing header information to be suppressed by the sending CS and reconstructed by the receiving CS */ + u8 u8PHSF[MAX_PHS_LENGTHS]; + /* PHSM Length Of The Service Flow */ + u8 u8PHSMLength; + /* PHS Mask for the SF */ + u8 u8PHSM[MAX_PHS_LENGTHS]; + /* 8bit Total number of bytes to be suppressed for the Service Flow */ + u8 u8PHSS; + /* 8bit Indicates whether or not Packet Header contents need to be verified prior to suppression */ + u8 u8PHSV; + /* Vendor Specific PHS param Length Of The Service Flow */ + u8 u8VendorSpecificPHSParamsLength; + /* Vendor Specific PHS param Of The Service Flow */ + u8 u8VendorSpecificPHSParams[VENDOR_PHS_PARAM_LENGTH]; + u8 u8Padding[2]; +}; + +struct bcm_convergence_types { + /* 8bit Phs Classfier Action Of The Service Flow */ + u8 u8ClassfierDSCAction; + /* 8bit Phs DSC Action Of The Service Flow */ + u8 u8PhsDSCAction; + /* 16bit Padding */ + u8 u8Padding[2]; + /* Packet classification rules structure */ + struct bcm_packet_class_rules cCPacketClassificationRule; + /* Payload header suppression rules structure */ + struct bcm_phs_rules cPhsRule; +}; + +struct bcm_connect_mgr_params { + /* 32bitSFID Of The Service Flow */ + u32 u32SFID; + /* 32bit Maximum Sustained Traffic Rate of the Service Flow */ + u32 u32MaxSustainedTrafficRate; + /* 32bit Maximum Traffic Burst allowed for the Service Flow */ + u32 u32MaxTrafficBurst; + /* 32bit Minimum Reserved Traffic Rate of the Service Flow */ + u32 u32MinReservedTrafficRate; + /* 32bit Tolerated Jitter of the Service Flow */ + u32 u32ToleratedJitter; + /* 32bit Maximum Latency of the Service Flow */ + u32 u32MaximumLatency; + /* 16bitCID Of The Service Flow */ + u16 u16CID; + /* 16bit SAID on which the service flow being set up shall be mapped */ + u16 u16TargetSAID; + /* 16bit ARQ window size negotiated */ + u16 u16ARQWindowSize; + /* 16bit Total Tx delay incl sending, receiving & processing delays */ + u16 u16ARQRetryTxTimeOut; + /* 16bit Total Rx delay incl sending, receiving & processing delays */ + u16 u16ARQRetryRxTimeOut; + /* 16bit ARQ block lifetime */ + u16 u16ARQBlockLifeTime; + /* 16bit ARQ Sync loss timeout */ + u16 u16ARQSyncLossTimeOut; + /* 16bit ARQ Purge timeout */ + u16 u16ARQRxPurgeTimeOut; + /* TODO::Remove this once we move to a new CORR2 driver + * brief Size of an ARQ block + */ + u16 u16ARQBlockSize; + /* #endif */ + /* 16bit Nominal interval b/w consecutive SDU arrivals at MAC SAP */ + u16 u16SDUInterArrivalTime; + /* 16bit Specifies the time base for rate measurement */ + u16 u16TimeBase; + /* 16bit Interval b/w Successive Grant oppurtunities */ + u16 u16UnsolicitedGrantInterval; + /* 16bit Interval b/w Successive Polling grant oppurtunities */ + u16 u16UnsolicitedPollingInterval; + /* internal var to get the overhead */ + u16 u16MacOverhead; + /* MBS contents Identifier */ + u16 u16MBSContentsID[MBS_CONTENTS_ID_LENGTH]; + /* MBS contents Identifier length */ + u8 u8MBSContentsIDLength; + /* ServiceClassName Length Of The Service Flow */ + u8 u8ServiceClassNameLength; + /* 32bytes ServiceClassName Of The Service Flow */ + u8 u8ServiceClassName[32]; + /* 8bit Indicates whether or not MBS service is requested for this Serivce Flow */ + u8 u8MBSService; + /* 8bit QOS Parameter Set specifies proper application of QoS parameters to Provisioned, Admitted and Active sets */ + u8 u8QosParamSet; + /* 8bit Traffic Priority Of the Service Flow */ + u8 u8TrafficPriority; + /* 8bit Uplink Grant Scheduling Type of The Service Flow */ + u8 u8ServiceFlowSchedulingType; + /* 8bit Request transmission Policy of the Service Flow */ + u8 u8RequesttransmissionPolicy; + /* 8bit Specifies whether SDUs for this Service flow are of FixedLength or Variable length */ + u8 u8FixedLengthVSVariableLengthSDUIndicator; + /* 8bit Length of the SDU for a fixed length SDU service flow */ + u8 u8SDUSize; + /* 8bit Indicates whether or not ARQ is requested for this connection */ + u8 u8ARQEnable; + /* < 8bit Indicates whether or not data has tobe delivered in order to higher layer */ + u8 u8ARQDeliverInOrder; + /* 8bit Receiver ARQ ACK processing time */ + u8 u8RxARQAckProcessingTime; + /* 8bit Convergence Sublayer Specification Of The Service Flow */ + u8 u8CSSpecification; + /* 8 bit Type of data delivery service */ + u8 u8TypeOfDataDeliveryService; + /* 8bit Specifies whether a service flow may generate Paging */ + u8 u8PagingPreference; + /* 8bit Indicates the MBS Zone through which the connection or virtual connection is valid */ + u8 u8MBSZoneIdentifierassignment; + /* 8bit Specifies whether traffic on SF should generate MOB_TRF_IND to MS in sleep mode */ + u8 u8TrafficIndicationPreference; + /* 8bit Speciifes the length of predefined Global QoS parameter set encoding for this SF */ + u8 u8GlobalServicesClassNameLength; + /* 6 byte Speciifes the predefined Global QoS parameter set encoding for this SF */ + u8 u8GlobalServicesClassName[GLOBAL_SF_CLASSNAME_LENGTH]; + /* 8bit Indicates whether or not SN feedback is enabled for the conn */ + u8 u8SNFeedbackEnabled; + /* Indicates the size of the Fragment Sequence Number for the connection */ + u8 u8FSNSize; + /* 8bit Number of CIDs in active BS list */ + u8 u8CIDAllocation4activeBSsLength; + /* CIDs of BS in the active list */ + u8 u8CIDAllocation4activeBSs[MAX_NUM_ACTIVE_BS]; + /* Specifies if PDU extended subheader should be applied on every PDU on this conn */ + u8 u8PDUSNExtendedSubheader4HarqReordering; + /* 8bit Specifies whether the connection uses HARQ or not */ + u8 u8HARQServiceFlows; + /* Specifies the length of Authorization token */ + u8 u8AuthTokenLength; + /* Specifies the Authorization token */ + u8 u8AuthToken[AUTH_TOKEN_LENGTH]; + /* specifes Number of HARQ channels used to carry data length */ + u8 u8HarqChannelMappingLength; + /* specifes HARQ channels used to carry data */ + u8 u8HARQChannelMapping[NUM_HARQ_CHANNELS]; + /* 8bit Length of Vendor Specific QoS Params */ + u8 u8VendorSpecificQoSParamLength; + /* 1byte Vendor Specific QoS Param Of The Service Flow */ + u8 u8VendorSpecificQoSParam[VENDOR_SPECIF_QOS_PARAM]; + /* indicates total classifiers in the SF */ + u8 u8TotalClassifiers; /* < Total number of valid classifiers */ + u8 bValid; /* < Validity flag */ + u8 u8Padding; /* < Padding byte */ + /* + * Structure for Convergence SubLayer Types with a maximum of 4 classifiers + */ + struct bcm_convergence_types cConvergenceSLTypes[MAX_CLASSIFIERS_IN_SF]; +}; + +struct bcm_add_request { + u8 u8Type; /* < Type */ + u8 eConnectionDir; /* < Connection direction */ + /* brief 16 bit TID */ + u16 u16TID; /* < 16bit TID */ + /* brief 16bitCID */ + u16 u16CID; /* < 16bit CID */ + /* brief 16bitVCID */ + u16 u16VCID; /* < 16bit VCID */ + struct bcm_connect_mgr_params *psfParameterSet; /* < connection manager parameters */ +}; + +struct bcm_add_indication { + u8 u8Type; /* < Type */ + u8 eConnectionDir; /* < Connection Direction */ + /* brief 16 bit TID */ + u16 u16TID; /* < TID */ + /* brief 16bitCID */ + u16 u16CID; /* < 16bitCID */ + /* brief 16bitVCID */ + u16 u16VCID; /* < 16bitVCID */ + struct bcm_connect_mgr_params *psfAuthorizedSet; /* Authorized set of connection manager parameters */ + struct bcm_connect_mgr_params *psfAdmittedSet; /* Admitted set of connection manager parameters */ + struct bcm_connect_mgr_params *psfActiveSet; /* Activeset of connection manager parameters */ + u8 u8CC; /* <Confirmation Code */ + u8 u8Padd; /* < 8-bit Padding */ + u16 u16Padd; /* < 16 bit Padding */ +}; + +struct bcm_del_request { + u8 u8Type; /* < Type */ + u8 u8Padding; /* < Padding byte */ + u16 u16TID; /* < TID */ + /* brief 32bitSFID */ + u32 u32SFID; /* < SFID */ +}; + +struct bcm_del_indication { + u8 u8Type; /* < Type */ + u8 u8Padding; /* < Padding */ + u16 u16TID; /* < TID */ + /* brief 16bitCID */ + u16 u16CID; /* < CID */ + /* brief 16bitVCID */ + u16 u16VCID; /* < VCID */ + /* brief 32bitSFID */ + u32 u32SFID; /* < SFID */ + /* brief 8bit Confirmation code */ + u8 u8ConfirmationCode; /* < Confirmation code */ + u8 u8Padding1[3]; /* < 3 byte Padding */ +}; + +struct bcm_stim_sfhostnotify { + u32 SFID; /* SFID of the service flow */ + u16 newCID; /* the new/changed CID */ + u16 VCID; /* Get new Vcid if the flow has been made active in CID update TLV, but was inactive earlier or the orig vcid */ + u8 RetainSF; /* Indication to Host if the SF is to be retained or deleted; if TRUE-retain else delete */ + u8 QoSParamSet; /* QoS paramset of the retained SF */ + u16 u16reserved; /* For byte alignment */ +}; + +#endif diff --git a/drivers/staging/bcm/headers.h b/drivers/staging/bcm/headers.h new file mode 100644 index 00000000000..6f3270cc417 --- /dev/null +++ b/drivers/staging/bcm/headers.h @@ -0,0 +1,78 @@ + +/******************************************************************* +* Headers.h +*******************************************************************/ +#ifndef __HEADERS_H__ +#define __HEADERS_H__ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/netdevice.h> +#include <linux/skbuff.h> +#include <linux/socket.h> +#include <linux/netfilter.h> +#include <linux/netfilter_ipv4.h> +#include <linux/if_arp.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/string.h> +#include <linux/etherdevice.h> +#include <linux/wait.h> +#include <linux/proc_fs.h> +#include <linux/interrupt.h> +#include <linux/stddef.h> +#include <linux/stat.h> +#include <linux/fcntl.h> +#include <linux/unistd.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/pagemap.h> +#include <linux/kthread.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include <linux/usb.h> +#include <linux/uaccess.h> +#include <net/ip.h> + +#include "Typedefs.h" +#include "Macros.h" +#include "HostMIBSInterface.h" +#include "cntrl_SignalingInterface.h" +#include "PHSDefines.h" +#include "led_control.h" +#include "Ioctl.h" +#include "nvm.h" +#include "target_params.h" +#include "Adapter.h" +#include "CmHost.h" +#include "DDRInit.h" +#include "Debug.h" +#include "IPv6ProtocolHdr.h" +#include "PHSModule.h" +#include "Protocol.h" +#include "Prototypes.h" +#include "Queue.h" +#include "vendorspecificextn.h" + +#include "InterfaceMacros.h" +#include "InterfaceAdapter.h" +#include "InterfaceIsr.h" +#include "InterfaceMisc.h" +#include "InterfaceRx.h" +#include "InterfaceTx.h" +#include "InterfaceIdleMode.h" +#include "InterfaceInit.h" + +#define DRV_NAME "beceem" +#define DEV_NAME "tarang" +#define DRV_DESCRIPTION "Beceem Communications Inc. WiMAX driver" +#define DRV_COPYRIGHT "Copyright 2010. Beceem Communications Inc" +#define DRV_VERSION "5.2.45" +#define PFX DRV_NAME " " + +extern struct class *bcm_class; + +#endif diff --git a/drivers/staging/bcm/hostmibs.c b/drivers/staging/bcm/hostmibs.c new file mode 100644 index 00000000000..42d9004e357 --- /dev/null +++ b/drivers/staging/bcm/hostmibs.c @@ -0,0 +1,150 @@ +/* + * File Name: hostmibs.c + * + * Author: Beceem Communications Pvt. Ltd + * + * Abstract: This file contains the routines to copy the statistics used by + * the driver to the Host MIBS structure and giving the same to Application. + */ + +#include "headers.h" + +INT ProcessGetHostMibs(struct bcm_mini_adapter *Adapter, + struct bcm_host_stats_mibs *pstHostMibs) +{ + struct bcm_phs_entry *pstServiceFlowEntry = NULL; + struct bcm_phs_rule *pstPhsRule = NULL; + struct bcm_phs_classifier_table *pstClassifierTable = NULL; + struct bcm_phs_classifier_entry *pstClassifierRule = NULL; + struct bcm_phs_extension *pDeviceExtension = &Adapter->stBCMPhsContext; + UINT nClassifierIndex = 0; + UINT nPhsTableIndex = 0; + UINT nSfIndex = 0; + UINT uiIndex = 0; + + if (pDeviceExtension == NULL) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, HOST_MIBS, + DBG_LVL_ALL, "Invalid Device Extension\n"); + return STATUS_FAILURE; + } + + /* Copy the classifier Table */ + for (nClassifierIndex = 0; nClassifierIndex < MAX_CLASSIFIERS; + nClassifierIndex++) { + if (Adapter->astClassifierTable[nClassifierIndex].bUsed == TRUE) + memcpy(&pstHostMibs->astClassifierTable[nClassifierIndex], + &Adapter->astClassifierTable[nClassifierIndex], + sizeof(struct bcm_mibs_classifier_rule)); + } + + /* Copy the SF Table */ + for (nSfIndex = 0; nSfIndex < NO_OF_QUEUES; nSfIndex++) { + if (Adapter->PackInfo[nSfIndex].bValid) { + memcpy(&pstHostMibs->astSFtable[nSfIndex], + &Adapter->PackInfo[nSfIndex], + sizeof(struct bcm_mibs_table)); + } else { + /* If index in not valid, + * don't process this for the PHS table. + * Go For the next entry. + */ + continue; + } + + /* Retrieve the SFID Entry Index for requested Service Flow */ + if (PHS_INVALID_TABLE_INDEX == + GetServiceFlowEntry(pDeviceExtension-> + pstServiceFlowPhsRulesTable, + Adapter->PackInfo[nSfIndex]. + usVCID_Value, &pstServiceFlowEntry)) + + continue; + + pstClassifierTable = pstServiceFlowEntry->pstClassifierTable; + + for (uiIndex = 0; uiIndex < MAX_PHSRULE_PER_SF; uiIndex++) { + pstClassifierRule = &pstClassifierTable->stActivePhsRulesList[uiIndex]; + + if (pstClassifierRule->bUsed) { + pstPhsRule = pstClassifierRule->pstPhsRule; + + pstHostMibs->astPhsRulesTable[nPhsTableIndex]. + ulSFID = Adapter->PackInfo[nSfIndex].ulSFID; + + memcpy(&pstHostMibs->astPhsRulesTable[nPhsTableIndex].u8PHSI, + &pstPhsRule->u8PHSI, + sizeof(struct bcm_phs_rule)); + nPhsTableIndex++; + + } + + } + + } + + /* Copy other Host Statistics parameters */ + pstHostMibs->stHostInfo.GoodTransmits = Adapter->dev->stats.tx_packets; + pstHostMibs->stHostInfo.GoodReceives = Adapter->dev->stats.rx_packets; + pstHostMibs->stHostInfo.CurrNumFreeDesc = + atomic_read(&Adapter->CurrNumFreeTxDesc); + pstHostMibs->stHostInfo.BEBucketSize = Adapter->BEBucketSize; + pstHostMibs->stHostInfo.rtPSBucketSize = Adapter->rtPSBucketSize; + pstHostMibs->stHostInfo.TimerActive = Adapter->TimerActive; + pstHostMibs->stHostInfo.u32TotalDSD = Adapter->u32TotalDSD; + + memcpy(pstHostMibs->stHostInfo.aTxPktSizeHist, Adapter->aTxPktSizeHist, + sizeof(UINT32) * MIBS_MAX_HIST_ENTRIES); + memcpy(pstHostMibs->stHostInfo.aRxPktSizeHist, Adapter->aRxPktSizeHist, + sizeof(UINT32) * MIBS_MAX_HIST_ENTRIES); + + return STATUS_SUCCESS; +} + +VOID GetDroppedAppCntrlPktMibs(struct bcm_host_stats_mibs *pstHostMibs, + struct bcm_tarang_data *pTarang) +{ + memcpy(&(pstHostMibs->stDroppedAppCntrlMsgs), + &(pTarang->stDroppedAppCntrlMsgs), + sizeof(struct bcm_mibs_dropped_cntrl_msg)); +} + +VOID CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter, + struct bcm_connect_mgr_params *psfLocalSet, + UINT uiSearchRuleIndex) +{ + struct bcm_mibs_parameters *t = &Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable; + + t->wmanIfSfid = psfLocalSet->u32SFID; + t->wmanIfCmnCpsMaxSustainedRate = psfLocalSet->u32MaxSustainedTrafficRate; + t->wmanIfCmnCpsMaxTrafficBurst = psfLocalSet->u32MaxTrafficBurst; + t->wmanIfCmnCpsMinReservedRate = psfLocalSet->u32MinReservedTrafficRate; + t->wmanIfCmnCpsToleratedJitter = psfLocalSet->u32ToleratedJitter; + t->wmanIfCmnCpsMaxLatency = psfLocalSet->u32MaximumLatency; + t->wmanIfCmnCpsFixedVsVariableSduInd = psfLocalSet->u8FixedLengthVSVariableLengthSDUIndicator; + t->wmanIfCmnCpsFixedVsVariableSduInd = ntohl(t->wmanIfCmnCpsFixedVsVariableSduInd); + t->wmanIfCmnCpsSduSize = psfLocalSet->u8SDUSize; + t->wmanIfCmnCpsSduSize = ntohl(t->wmanIfCmnCpsSduSize); + t->wmanIfCmnCpsSfSchedulingType = psfLocalSet->u8ServiceFlowSchedulingType; + t->wmanIfCmnCpsSfSchedulingType = ntohl(t->wmanIfCmnCpsSfSchedulingType); + t->wmanIfCmnCpsArqEnable = psfLocalSet->u8ARQEnable; + t->wmanIfCmnCpsArqEnable = ntohl(t->wmanIfCmnCpsArqEnable); + t->wmanIfCmnCpsArqWindowSize = ntohs(psfLocalSet->u16ARQWindowSize); + t->wmanIfCmnCpsArqWindowSize = ntohl(t->wmanIfCmnCpsArqWindowSize); + t->wmanIfCmnCpsArqBlockLifetime = ntohs(psfLocalSet->u16ARQBlockLifeTime); + t->wmanIfCmnCpsArqBlockLifetime = ntohl(t->wmanIfCmnCpsArqBlockLifetime); + t->wmanIfCmnCpsArqSyncLossTimeout = ntohs(psfLocalSet->u16ARQSyncLossTimeOut); + t->wmanIfCmnCpsArqSyncLossTimeout = ntohl(t->wmanIfCmnCpsArqSyncLossTimeout); + t->wmanIfCmnCpsArqDeliverInOrder = psfLocalSet->u8ARQDeliverInOrder; + t->wmanIfCmnCpsArqDeliverInOrder = ntohl(t->wmanIfCmnCpsArqDeliverInOrder); + t->wmanIfCmnCpsArqRxPurgeTimeout = ntohs(psfLocalSet->u16ARQRxPurgeTimeOut); + t->wmanIfCmnCpsArqRxPurgeTimeout = ntohl(t->wmanIfCmnCpsArqRxPurgeTimeout); + t->wmanIfCmnCpsArqBlockSize = ntohs(psfLocalSet->u16ARQBlockSize); + t->wmanIfCmnCpsArqBlockSize = ntohl(t->wmanIfCmnCpsArqBlockSize); + t->wmanIfCmnCpsReqTxPolicy = psfLocalSet->u8RequesttransmissionPolicy; + t->wmanIfCmnCpsReqTxPolicy = ntohl(t->wmanIfCmnCpsReqTxPolicy); + t->wmanIfCmnSfCsSpecification = psfLocalSet->u8CSSpecification; + t->wmanIfCmnSfCsSpecification = ntohl(t->wmanIfCmnSfCsSpecification); + t->wmanIfCmnCpsTargetSaid = ntohs(psfLocalSet->u16TargetSAID); + t->wmanIfCmnCpsTargetSaid = ntohl(t->wmanIfCmnCpsTargetSaid); + +} diff --git a/drivers/staging/bcm/led_control.c b/drivers/staging/bcm/led_control.c new file mode 100644 index 00000000000..eee4f4795a7 --- /dev/null +++ b/drivers/staging/bcm/led_control.c @@ -0,0 +1,916 @@ +#include "headers.h" + +#define STATUS_IMAGE_CHECKSUM_MISMATCH -199 +#define EVENT_SIGNALED 1 + +static B_UINT16 CFG_CalculateChecksum(B_UINT8 *pu8Buffer, B_UINT32 u32Size) +{ + B_UINT16 u16CheckSum = 0; + while (u32Size--) { + u16CheckSum += (B_UINT8)~(*pu8Buffer); + pu8Buffer++; + } + return u16CheckSum; +} + +bool IsReqGpioIsLedInNVM(struct bcm_mini_adapter *Adapter, UINT gpios) +{ + INT Status; + Status = (Adapter->gpioBitMap & gpios) ^ gpios; + if (Status) + return false; + else + return TRUE; +} + +static INT LED_Blink(struct bcm_mini_adapter *Adapter, UINT GPIO_Num, UCHAR uiLedIndex, + ULONG timeout, INT num_of_time, enum bcm_led_events currdriverstate) +{ + int Status = STATUS_SUCCESS; + bool bInfinite = false; + + /* Check if num_of_time is -ve. If yes, blink led in infinite loop */ + if (num_of_time < 0) { + bInfinite = TRUE; + num_of_time = 1; + } + while (num_of_time) { + if (currdriverstate == Adapter->DriverState) + TURN_ON_LED(GPIO_Num, uiLedIndex); + + /* Wait for timeout after setting on the LED */ + Status = wait_event_interruptible_timeout( + Adapter->LEDInfo.notify_led_event, + currdriverstate != Adapter->DriverState || + kthread_should_stop(), + msecs_to_jiffies(timeout)); + + if (kthread_should_stop()) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "Led thread got signal to exit..hence exiting"); + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_DISABLED; + TURN_OFF_LED(GPIO_Num, uiLedIndex); + Status = EVENT_SIGNALED; + break; + } + if (Status) { + TURN_OFF_LED(GPIO_Num, uiLedIndex); + Status = EVENT_SIGNALED; + break; + } + + TURN_OFF_LED(GPIO_Num, uiLedIndex); + Status = wait_event_interruptible_timeout( + Adapter->LEDInfo.notify_led_event, + currdriverstate != Adapter->DriverState || + kthread_should_stop(), + msecs_to_jiffies(timeout)); + if (bInfinite == false) + num_of_time--; + } + return Status; +} + +static INT ScaleRateofTransfer(ULONG rate) +{ + if (rate <= 3) + return rate; + else if ((rate > 3) && (rate <= 100)) + return 5; + else if ((rate > 100) && (rate <= 200)) + return 6; + else if ((rate > 200) && (rate <= 300)) + return 7; + else if ((rate > 300) && (rate <= 400)) + return 8; + else if ((rate > 400) && (rate <= 500)) + return 9; + else if ((rate > 500) && (rate <= 600)) + return 10; + else + return MAX_NUM_OF_BLINKS; +} + + + +static INT LED_Proportional_Blink(struct bcm_mini_adapter *Adapter, UCHAR GPIO_Num_tx, + UCHAR uiTxLedIndex, UCHAR GPIO_Num_rx, UCHAR uiRxLedIndex, + enum bcm_led_events currdriverstate) +{ + /* Initial values of TX and RX packets */ + ULONG64 Initial_num_of_packts_tx = 0, Initial_num_of_packts_rx = 0; + /* values of TX and RX packets after 1 sec */ + ULONG64 Final_num_of_packts_tx = 0, Final_num_of_packts_rx = 0; + /* Rate of transfer of Tx and Rx in 1 sec */ + ULONG64 rate_of_transfer_tx = 0, rate_of_transfer_rx = 0; + int Status = STATUS_SUCCESS; + INT num_of_time = 0, num_of_time_tx = 0, num_of_time_rx = 0; + UINT remDelay = 0; + bool bBlinkBothLED = TRUE; + /* UINT GPIO_num = DISABLE_GPIO_NUM; */ + ulong timeout = 0; + + /* Read initial value of packets sent/received */ + Initial_num_of_packts_tx = Adapter->dev->stats.tx_packets; + Initial_num_of_packts_rx = Adapter->dev->stats.rx_packets; + + /* Scale the rate of transfer to no of blinks. */ + num_of_time_tx = ScaleRateofTransfer((ULONG)rate_of_transfer_tx); + num_of_time_rx = ScaleRateofTransfer((ULONG)rate_of_transfer_rx); + + while ((Adapter->device_removed == false)) { + timeout = 50; + /* + * Blink Tx and Rx LED when both Tx and Rx is + * in normal bandwidth + */ + if (bBlinkBothLED) { + /* + * Assign minimum number of blinks of + * either Tx or Rx. + */ + if (num_of_time_tx > num_of_time_rx) + num_of_time = num_of_time_rx; + else + num_of_time = num_of_time_tx; + if (num_of_time > 0) { + /* Blink both Tx and Rx LEDs */ + if (LED_Blink(Adapter, 1 << GPIO_Num_tx, + uiTxLedIndex, timeout, + num_of_time, currdriverstate) + == EVENT_SIGNALED) + return EVENT_SIGNALED; + + if (LED_Blink(Adapter, 1 << GPIO_Num_rx, + uiRxLedIndex, timeout, + num_of_time, currdriverstate) + == EVENT_SIGNALED) + return EVENT_SIGNALED; + + } + + if (num_of_time == num_of_time_tx) { + /* Blink pending rate of Rx */ + if (LED_Blink(Adapter, (1 << GPIO_Num_rx), + uiRxLedIndex, timeout, + num_of_time_rx-num_of_time, + currdriverstate) + == EVENT_SIGNALED) + return EVENT_SIGNALED; + + num_of_time = num_of_time_rx; + } else { + /* Blink pending rate of Tx */ + if (LED_Blink(Adapter, 1 << GPIO_Num_tx, + uiTxLedIndex, timeout, + num_of_time_tx-num_of_time, + currdriverstate) + == EVENT_SIGNALED) + return EVENT_SIGNALED; + + num_of_time = num_of_time_tx; + } + } else { + if (num_of_time == num_of_time_tx) { + /* Blink pending rate of Rx */ + if (LED_Blink(Adapter, 1 << GPIO_Num_tx, + uiTxLedIndex, timeout, + num_of_time, currdriverstate) + == EVENT_SIGNALED) + return EVENT_SIGNALED; + } else { + /* Blink pending rate of Tx */ + if (LED_Blink(Adapter, 1 << GPIO_Num_rx, + uiRxLedIndex, timeout, + num_of_time, currdriverstate) + == EVENT_SIGNALED) + return EVENT_SIGNALED; + } + } + + /* + * If Tx/Rx rate is less than maximum blinks per second, + * wait till delay completes to 1 second + */ + remDelay = MAX_NUM_OF_BLINKS - num_of_time; + if (remDelay > 0) { + timeout = 100 * remDelay; + Status = wait_event_interruptible_timeout( + Adapter->LEDInfo.notify_led_event, + currdriverstate != Adapter->DriverState + || kthread_should_stop(), + msecs_to_jiffies(timeout)); + + if (kthread_should_stop()) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + LED_DUMP_INFO, DBG_LVL_ALL, + "Led thread got signal to exit..hence exiting"); + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_DISABLED; + return EVENT_SIGNALED; + } + if (Status) + return EVENT_SIGNALED; + } + + /* Turn off both Tx and Rx LEDs before next second */ + TURN_OFF_LED(1 << GPIO_Num_tx, uiTxLedIndex); + TURN_OFF_LED(1 << GPIO_Num_rx, uiTxLedIndex); + + /* + * Read the Tx & Rx packets transmission after 1 second and + * calculate rate of transfer + */ + Final_num_of_packts_tx = Adapter->dev->stats.tx_packets; + Final_num_of_packts_rx = Adapter->dev->stats.rx_packets; + + rate_of_transfer_tx = Final_num_of_packts_tx - + Initial_num_of_packts_tx; + rate_of_transfer_rx = Final_num_of_packts_rx - + Initial_num_of_packts_rx; + + /* Read initial value of packets sent/received */ + Initial_num_of_packts_tx = Final_num_of_packts_tx; + Initial_num_of_packts_rx = Final_num_of_packts_rx; + + /* Scale the rate of transfer to no of blinks. */ + num_of_time_tx = + ScaleRateofTransfer((ULONG)rate_of_transfer_tx); + num_of_time_rx = + ScaleRateofTransfer((ULONG)rate_of_transfer_rx); + + } + return Status; +} + +/* + * ----------------------------------------------------------------------------- + * Procedure: ValidateDSDParamsChecksum + * + * Description: Reads DSD Params and validates checkusm. + * + * Arguments: + * Adapter - Pointer to Adapter structure. + * ulParamOffset - Start offset of the DSD parameter to be read and + * validated. + * usParamLen - Length of the DSD Parameter. + * + * Returns: + * <OSAL_STATUS_CODE> + * ----------------------------------------------------------------------------- + */ +static INT ValidateDSDParamsChecksum(struct bcm_mini_adapter *Adapter, ULONG ulParamOffset, + USHORT usParamLen) +{ + INT Status = STATUS_SUCCESS; + PUCHAR puBuffer = NULL; + USHORT usChksmOrg = 0; + USHORT usChecksumCalculated = 0; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "LED Thread:ValidateDSDParamsChecksum: 0x%lx 0x%X", + ulParamOffset, usParamLen); + + puBuffer = kmalloc(usParamLen, GFP_KERNEL); + if (!puBuffer) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "LED Thread: ValidateDSDParamsChecksum Allocation failed"); + return -ENOMEM; + + } + + /* Read the DSD data from the parameter offset. */ + if (STATUS_SUCCESS != BeceemNVMRead(Adapter, (PUINT)puBuffer, + ulParamOffset, usParamLen)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "LED Thread: ValidateDSDParamsChecksum BeceemNVMRead failed"); + Status = STATUS_IMAGE_CHECKSUM_MISMATCH; + goto exit; + } + + /* Calculate the checksum of the data read from the DSD parameter. */ + usChecksumCalculated = CFG_CalculateChecksum(puBuffer, usParamLen); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "LED Thread: usCheckSumCalculated = 0x%x\n", + usChecksumCalculated); + + /* + * End of the DSD parameter will have a TWO bytes checksum stored in it. + * Read it and compare with the calculated Checksum. + */ + if (STATUS_SUCCESS != BeceemNVMRead(Adapter, (PUINT)&usChksmOrg, + ulParamOffset+usParamLen, 2)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "LED Thread: ValidateDSDParamsChecksum BeceemNVMRead failed"); + Status = STATUS_IMAGE_CHECKSUM_MISMATCH; + goto exit; + } + usChksmOrg = ntohs(usChksmOrg); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "LED Thread: usChksmOrg = 0x%x", usChksmOrg); + + /* + * Compare the checksum calculated with the checksum read + * from DSD section + */ + if (usChecksumCalculated ^ usChksmOrg) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "LED Thread: ValidateDSDParamsChecksum: Checksums don't match"); + Status = STATUS_IMAGE_CHECKSUM_MISMATCH; + goto exit; + } + +exit: + kfree(puBuffer); + return Status; +} + + +/* + * ----------------------------------------------------------------------------- + * Procedure: ValidateHWParmStructure + * + * Description: Validates HW Parameters. + * + * Arguments: + * Adapter - Pointer to Adapter structure. + * ulHwParamOffset - Start offset of the HW parameter Section to be read + * and validated. + * + * Returns: + * <OSAL_STATUS_CODE> + * ----------------------------------------------------------------------------- + */ +static INT ValidateHWParmStructure(struct bcm_mini_adapter *Adapter, ULONG ulHwParamOffset) +{ + + INT Status = STATUS_SUCCESS; + USHORT HwParamLen = 0; + /* + * Add DSD start offset to the hwParamOffset to get + * the actual address. + */ + ulHwParamOffset += DSD_START_OFFSET; + + /* Read the Length of HW_PARAM structure */ + BeceemNVMRead(Adapter, (PUINT)&HwParamLen, ulHwParamOffset, 2); + HwParamLen = ntohs(HwParamLen); + if (0 == HwParamLen || HwParamLen > Adapter->uiNVMDSDSize) + return STATUS_IMAGE_CHECKSUM_MISMATCH; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "LED Thread:HwParamLen = 0x%x", HwParamLen); + Status = ValidateDSDParamsChecksum(Adapter, ulHwParamOffset, + HwParamLen); + return Status; +} /* ValidateHWParmStructure() */ + +static int ReadLEDInformationFromEEPROM(struct bcm_mini_adapter *Adapter, + UCHAR GPIO_Array[]) +{ + int Status = STATUS_SUCCESS; + + ULONG dwReadValue = 0; + USHORT usHwParamData = 0; + USHORT usEEPROMVersion = 0; + UCHAR ucIndex = 0; + UCHAR ucGPIOInfo[32] = {0}; + + BeceemNVMRead(Adapter, (PUINT)&usEEPROMVersion, + EEPROM_VERSION_OFFSET, 2); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "usEEPROMVersion: Minor:0x%X Major:0x%x", + usEEPROMVersion&0xFF, ((usEEPROMVersion>>8)&0xFF)); + + + if (((usEEPROMVersion>>8)&0xFF) < EEPROM_MAP5_MAJORVERSION) { + BeceemNVMRead(Adapter, (PUINT)&usHwParamData, + EEPROM_HW_PARAM_POINTER_ADDRESS, 2); + usHwParamData = ntohs(usHwParamData); + dwReadValue = usHwParamData; + } else { + /* + * Validate Compatibility section and then read HW param + * if compatibility section is valid. + */ + Status = ValidateDSDParamsChecksum(Adapter, + DSD_START_OFFSET, + COMPATIBILITY_SECTION_LENGTH_MAP5); + + if (Status != STATUS_SUCCESS) + return Status; + + BeceemNVMRead(Adapter, (PUINT)&dwReadValue, + EEPROM_HW_PARAM_POINTER_ADDRRES_MAP5, 4); + dwReadValue = ntohl(dwReadValue); + } + + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "LED Thread: Start address of HW_PARAM structure = 0x%lx", + dwReadValue); + + /* + * Validate if the address read out is within the DSD. + * Adapter->uiNVMDSDSize gives whole DSD size inclusive of Autoinit. + * lower limit should be above DSD_START_OFFSET and + * upper limit should be below (Adapter->uiNVMDSDSize-DSD_START_OFFSET) + */ + if (dwReadValue < DSD_START_OFFSET || + dwReadValue > (Adapter->uiNVMDSDSize-DSD_START_OFFSET)) + return STATUS_IMAGE_CHECKSUM_MISMATCH; + + Status = ValidateHWParmStructure(Adapter, dwReadValue); + if (Status) + return Status; + + /* + * Add DSD_START_OFFSET to the offset read from the EEPROM. + * This will give the actual start HW Parameters start address. + * To read GPIO section, add GPIO offset further. + */ + + dwReadValue += + DSD_START_OFFSET; /* = start address of hw param section. */ + dwReadValue += GPIO_SECTION_START_OFFSET; + /* = GPIO start offset within HW Param section. */ + + /* + * Read the GPIO values for 32 GPIOs from EEPROM and map the function + * number to GPIO pin number to GPIO_Array + */ + BeceemNVMRead(Adapter, (UINT *)ucGPIOInfo, dwReadValue, 32); + for (ucIndex = 0; ucIndex < 32; ucIndex++) { + + switch (ucGPIOInfo[ucIndex]) { + case RED_LED: + GPIO_Array[RED_LED] = ucIndex; + Adapter->gpioBitMap |= (1 << ucIndex); + break; + case BLUE_LED: + GPIO_Array[BLUE_LED] = ucIndex; + Adapter->gpioBitMap |= (1 << ucIndex); + break; + case YELLOW_LED: + GPIO_Array[YELLOW_LED] = ucIndex; + Adapter->gpioBitMap |= (1 << ucIndex); + break; + case GREEN_LED: + GPIO_Array[GREEN_LED] = ucIndex; + Adapter->gpioBitMap |= (1 << ucIndex); + break; + default: + break; + } + + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "GPIO's bit map correspond to LED :0x%X", Adapter->gpioBitMap); + return Status; +} + + +static int ReadConfigFileStructure(struct bcm_mini_adapter *Adapter, + bool *bEnableThread) +{ + int Status = STATUS_SUCCESS; + /* Array to store GPIO numbers from EEPROM */ + UCHAR GPIO_Array[NUM_OF_LEDS+1]; + UINT uiIndex = 0; + UINT uiNum_of_LED_Type = 0; + PUCHAR puCFGData = NULL; + UCHAR bData = 0; + memset(GPIO_Array, DISABLE_GPIO_NUM, NUM_OF_LEDS+1); + + if (!Adapter->pstargetparams || IS_ERR(Adapter->pstargetparams)) { + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, "Target Params not Avail.\n"); + return -ENOENT; + } + + /* Populate GPIO_Array with GPIO numbers for LED functions */ + /* Read the GPIO numbers from EEPROM */ + Status = ReadLEDInformationFromEEPROM(Adapter, GPIO_Array); + if (Status == STATUS_IMAGE_CHECKSUM_MISMATCH) { + *bEnableThread = false; + return STATUS_SUCCESS; + } else if (Status) { + *bEnableThread = false; + return Status; + } + + /* + * CONFIG file read successfully. Deallocate the memory of + * uiFileNameBufferSize + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, DBG_LVL_ALL, + "LED Thread: Config file read successfully\n"); + puCFGData = (PUCHAR) &Adapter->pstargetparams->HostDrvrConfig1; + + /* + * Offset for HostDrvConfig1, HostDrvConfig2, HostDrvConfig3 which + * will have the information of LED type, LED on state for different + * driver state and LED blink state. + */ + + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { + bData = *puCFGData; + + /* + * Check Bit 8 for polarity. If it is set, + * polarity is reverse polarity + */ + if (bData & 0x80) { + Adapter->LEDInfo.LEDState[uiIndex].BitPolarity = 0; + /* unset the bit 8 */ + bData = bData & 0x7f; + } + + Adapter->LEDInfo.LEDState[uiIndex].LED_Type = bData; + if (bData <= NUM_OF_LEDS) + Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num = + GPIO_Array[bData]; + else + Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num = + DISABLE_GPIO_NUM; + + puCFGData++; + bData = *puCFGData; + Adapter->LEDInfo.LEDState[uiIndex].LED_On_State = bData; + puCFGData++; + bData = *puCFGData; + Adapter->LEDInfo.LEDState[uiIndex].LED_Blink_State = bData; + puCFGData++; + } + + /* + * Check if all the LED settings are disabled. If it is disabled, + * dont launch the LED control thread. + */ + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { + if ((Adapter->LEDInfo.LEDState[uiIndex].LED_Type == DISABLE_GPIO_NUM) || + (Adapter->LEDInfo.LEDState[uiIndex].LED_Type == 0x7f) || + (Adapter->LEDInfo.LEDState[uiIndex].LED_Type == 0)) + uiNum_of_LED_Type++; + } + if (uiNum_of_LED_Type >= NUM_OF_LEDS) + *bEnableThread = false; + + return Status; +} + +/* + * ----------------------------------------------------------------------------- + * Procedure: LedGpioInit + * + * Description: Initializes LED GPIOs. Makes the LED GPIOs to OUTPUT mode + * and make the initial state to be OFF. + * + * Arguments: + * Adapter - Pointer to MINI_ADAPTER structure. + * + * Returns: VOID + * + * ----------------------------------------------------------------------------- + */ +static VOID LedGpioInit(struct bcm_mini_adapter *Adapter) +{ + UINT uiResetValue = 0; + UINT uiIndex = 0; + + /* Set all LED GPIO Mode to output mode */ + if (rdmalt(Adapter, GPIO_MODE_REGISTER, &uiResetValue, + sizeof(uiResetValue)) < 0) + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, "LED Thread: RDM Failed\n"); + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { + if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != + DISABLE_GPIO_NUM) + uiResetValue |= (1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num); + TURN_OFF_LED(1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num, + uiIndex); + } + if (wrmalt(Adapter, GPIO_MODE_REGISTER, &uiResetValue, + sizeof(uiResetValue)) < 0) + BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, "LED Thread: WRM Failed\n"); + + Adapter->LEDInfo.bIdle_led_off = false; +} + +static INT BcmGetGPIOPinInfo(struct bcm_mini_adapter *Adapter, UCHAR *GPIO_num_tx, + UCHAR *GPIO_num_rx, UCHAR *uiLedTxIndex, UCHAR *uiLedRxIndex, + enum bcm_led_events currdriverstate) +{ + UINT uiIndex = 0; + + *GPIO_num_tx = DISABLE_GPIO_NUM; + *GPIO_num_rx = DISABLE_GPIO_NUM; + + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { + + if ((currdriverstate == NORMAL_OPERATION) || + (currdriverstate == IDLEMODE_EXIT) || + (currdriverstate == FW_DOWNLOAD)) { + if (Adapter->LEDInfo.LEDState[uiIndex].LED_Blink_State & + currdriverstate) { + if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num + != DISABLE_GPIO_NUM) { + if (*GPIO_num_tx == DISABLE_GPIO_NUM) { + *GPIO_num_tx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num; + *uiLedTxIndex = uiIndex; + } else { + *GPIO_num_rx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num; + *uiLedRxIndex = uiIndex; + } + } + } + } else { + if (Adapter->LEDInfo.LEDState[uiIndex].LED_On_State + & currdriverstate) { + if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num + != DISABLE_GPIO_NUM) { + *GPIO_num_tx = Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num; + *uiLedTxIndex = uiIndex; + } + } + } + } + return STATUS_SUCCESS; +} +static VOID LEDControlThread(struct bcm_mini_adapter *Adapter) +{ + UINT uiIndex = 0; + UCHAR GPIO_num = 0; + UCHAR uiLedIndex = 0; + UINT uiResetValue = 0; + enum bcm_led_events currdriverstate = 0; + ulong timeout = 0; + + INT Status = 0; + + UCHAR dummyGPIONum = 0; + UCHAR dummyIndex = 0; + + /* currdriverstate = Adapter->DriverState; */ + Adapter->LEDInfo.bIdleMode_tx_from_host = false; + + /* + * Wait till event is triggered + * + * wait_event(Adapter->LEDInfo.notify_led_event, + * currdriverstate!= Adapter->DriverState); + */ + + GPIO_num = DISABLE_GPIO_NUM; + + while (TRUE) { + /* Wait till event is triggered */ + if ((GPIO_num == DISABLE_GPIO_NUM) + || + ((currdriverstate != FW_DOWNLOAD) && + (currdriverstate != NORMAL_OPERATION) && + (currdriverstate != LOWPOWER_MODE_ENTER)) + || + (currdriverstate == LED_THREAD_INACTIVE)) + Status = wait_event_interruptible( + Adapter->LEDInfo.notify_led_event, + currdriverstate != Adapter->DriverState + || kthread_should_stop()); + + if (kthread_should_stop() || Adapter->device_removed) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "Led thread got signal to exit..hence exiting"); + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_DISABLED; + TURN_OFF_LED(1 << GPIO_num, uiLedIndex); + return; /* STATUS_FAILURE; */ + } + + if (GPIO_num != DISABLE_GPIO_NUM) + TURN_OFF_LED(1 << GPIO_num, uiLedIndex); + + if (Adapter->LEDInfo.bLedInitDone == false) { + LedGpioInit(Adapter); + Adapter->LEDInfo.bLedInitDone = TRUE; + } + + switch (Adapter->DriverState) { + case DRIVER_INIT: + currdriverstate = DRIVER_INIT; + /* Adapter->DriverState; */ + BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, + &uiLedIndex, &dummyIndex, currdriverstate); + + if (GPIO_num != DISABLE_GPIO_NUM) + TURN_ON_LED(1 << GPIO_num, uiLedIndex); + + break; + case FW_DOWNLOAD: + /* + * BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, + * LED_DUMP_INFO, DBG_LVL_ALL, + * "LED Thread: FW_DN_DONE called\n"); + */ + currdriverstate = FW_DOWNLOAD; + BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, + &uiLedIndex, &dummyIndex, currdriverstate); + + if (GPIO_num != DISABLE_GPIO_NUM) { + timeout = 50; + LED_Blink(Adapter, 1 << GPIO_num, uiLedIndex, + timeout, -1, currdriverstate); + } + break; + case FW_DOWNLOAD_DONE: + currdriverstate = FW_DOWNLOAD_DONE; + BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, + &uiLedIndex, &dummyIndex, currdriverstate); + if (GPIO_num != DISABLE_GPIO_NUM) + TURN_ON_LED(1 << GPIO_num, uiLedIndex); + break; + + case SHUTDOWN_EXIT: + /* + * no break, continue to NO_NETWORK_ENTRY + * state as well. + */ + case NO_NETWORK_ENTRY: + currdriverstate = NO_NETWORK_ENTRY; + BcmGetGPIOPinInfo(Adapter, &GPIO_num, &dummyGPIONum, + &uiLedIndex, &dummyGPIONum, currdriverstate); + if (GPIO_num != DISABLE_GPIO_NUM) + TURN_ON_LED(1 << GPIO_num, uiLedIndex); + break; + case NORMAL_OPERATION: + { + UCHAR GPIO_num_tx = DISABLE_GPIO_NUM; + UCHAR GPIO_num_rx = DISABLE_GPIO_NUM; + UCHAR uiLEDTx = 0; + UCHAR uiLEDRx = 0; + currdriverstate = NORMAL_OPERATION; + Adapter->LEDInfo.bIdle_led_off = false; + + BcmGetGPIOPinInfo(Adapter, &GPIO_num_tx, + &GPIO_num_rx, &uiLEDTx, &uiLEDRx, + currdriverstate); + if ((GPIO_num_tx == DISABLE_GPIO_NUM) && + (GPIO_num_rx == + DISABLE_GPIO_NUM)) { + GPIO_num = DISABLE_GPIO_NUM; + } else { + /* + * If single LED is selected, use same + * for both Tx and Rx + */ + if (GPIO_num_tx == DISABLE_GPIO_NUM) { + GPIO_num_tx = GPIO_num_rx; + uiLEDTx = uiLEDRx; + } else if (GPIO_num_rx == + DISABLE_GPIO_NUM) { + GPIO_num_rx = GPIO_num_tx; + uiLEDRx = uiLEDTx; + } + /* + * Blink the LED in proportionate + * to Tx and Rx transmissions. + */ + LED_Proportional_Blink(Adapter, + GPIO_num_tx, uiLEDTx, + GPIO_num_rx, uiLEDRx, + currdriverstate); + } + } + break; + case LOWPOWER_MODE_ENTER: + currdriverstate = LOWPOWER_MODE_ENTER; + if (DEVICE_POWERSAVE_MODE_AS_MANUAL_CLOCK_GATING == + Adapter->ulPowerSaveMode) { + /* Turn OFF all the LED */ + uiResetValue = 0; + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { + if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num != DISABLE_GPIO_NUM) + TURN_OFF_LED((1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num), uiIndex); + } + + } + /* Turn off LED And WAKE-UP for Sendinf IDLE mode ACK */ + Adapter->LEDInfo.bLedInitDone = false; + Adapter->LEDInfo.bIdle_led_off = TRUE; + wake_up(&Adapter->LEDInfo.idleModeSyncEvent); + GPIO_num = DISABLE_GPIO_NUM; + break; + case IDLEMODE_CONTINUE: + currdriverstate = IDLEMODE_CONTINUE; + GPIO_num = DISABLE_GPIO_NUM; + break; + case IDLEMODE_EXIT: + break; + case DRIVER_HALT: + currdriverstate = DRIVER_HALT; + GPIO_num = DISABLE_GPIO_NUM; + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { + if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num + != DISABLE_GPIO_NUM) + TURN_OFF_LED((1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num), uiIndex); + } + /* Adapter->DriverState = DRIVER_INIT; */ + break; + case LED_THREAD_INACTIVE: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, "InActivating LED thread..."); + currdriverstate = LED_THREAD_INACTIVE; + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_RUNNING_INACTIVELY; + Adapter->LEDInfo.bLedInitDone = false; + /* disable ALL LED */ + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) { + if (Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num + != DISABLE_GPIO_NUM) + TURN_OFF_LED((1 << Adapter->LEDInfo.LEDState[uiIndex].GPIO_Num), uiIndex); + } + break; + case LED_THREAD_ACTIVE: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, "Activating LED thread again..."); + if (Adapter->LinkUpStatus == false) + Adapter->DriverState = NO_NETWORK_ENTRY; + else + Adapter->DriverState = NORMAL_OPERATION; + + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_RUNNING_ACTIVELY; + break; + /* return; */ + default: + break; + } + } + Adapter->LEDInfo.led_thread_running = BCM_LED_THREAD_DISABLED; +} + +int InitLedSettings(struct bcm_mini_adapter *Adapter) +{ + int Status = STATUS_SUCCESS; + bool bEnableThread = TRUE; + UCHAR uiIndex = 0; + + /* + * Initially set BitPolarity to normal polarity. The bit 8 of LED type + * is used to change the polarity of the LED. + */ + + for (uiIndex = 0; uiIndex < NUM_OF_LEDS; uiIndex++) + Adapter->LEDInfo.LEDState[uiIndex].BitPolarity = 1; + + /* + * Read the LED settings of CONFIG file and map it + * to GPIO numbers in EEPROM + */ + Status = ReadConfigFileStructure(Adapter, &bEnableThread); + if (STATUS_SUCCESS != Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "LED Thread: FAILED in ReadConfigFileStructure\n"); + return Status; + } + + if (Adapter->LEDInfo.led_thread_running) { + if (bEnableThread) { + ; + } else { + Adapter->DriverState = DRIVER_HALT; + wake_up(&Adapter->LEDInfo.notify_led_event); + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_DISABLED; + } + + } else if (bEnableThread) { + /* Create secondary thread to handle the LEDs */ + init_waitqueue_head(&Adapter->LEDInfo.notify_led_event); + init_waitqueue_head(&Adapter->LEDInfo.idleModeSyncEvent); + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_RUNNING_ACTIVELY; + Adapter->LEDInfo.bIdle_led_off = false; + Adapter->LEDInfo.led_cntrl_threadid = + kthread_run((int (*)(void *)) LEDControlThread, + Adapter, "led_control_thread"); + if (IS_ERR(Adapter->LEDInfo.led_cntrl_threadid)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, LED_DUMP_INFO, + DBG_LVL_ALL, + "Not able to spawn Kernel Thread\n"); + Adapter->LEDInfo.led_thread_running = + BCM_LED_THREAD_DISABLED; + return PTR_ERR(Adapter->LEDInfo.led_cntrl_threadid); + } + } + return Status; +} diff --git a/drivers/staging/bcm/led_control.h b/drivers/staging/bcm/led_control.h new file mode 100644 index 00000000000..bae40e22e11 --- /dev/null +++ b/drivers/staging/bcm/led_control.h @@ -0,0 +1,84 @@ +#ifndef _LED_CONTROL_H +#define _LED_CONTROL_H + +#define NUM_OF_LEDS 4 +#define DSD_START_OFFSET 0x0200 +#define EEPROM_VERSION_OFFSET 0x020E +#define EEPROM_HW_PARAM_POINTER_ADDRESS 0x0218 +#define EEPROM_HW_PARAM_POINTER_ADDRRES_MAP5 0x0220 +#define GPIO_SECTION_START_OFFSET 0x03 +#define COMPATIBILITY_SECTION_LENGTH 42 +#define COMPATIBILITY_SECTION_LENGTH_MAP5 84 +#define EEPROM_MAP5_MAJORVERSION 5 +#define EEPROM_MAP5_MINORVERSION 0 +#define MAX_NUM_OF_BLINKS 10 +#define NUM_OF_GPIO_PINS 16 +#define DISABLE_GPIO_NUM 0xFF +#define EVENT_SIGNALED 1 +#define MAX_FILE_NAME_BUFFER_SIZE 100 + +#define TURN_ON_LED(GPIO, index) do { \ + unsigned int gpio_val = GPIO; \ + (Adapter->LEDInfo.LEDState[index].BitPolarity == 1) ? \ + wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_SET_REG, &gpio_val, sizeof(gpio_val)) : \ + wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_CLR_REG, &gpio_val, sizeof(gpio_val)); \ + } while (0) + +#define TURN_OFF_LED(GPIO, index) do { \ + unsigned int gpio_val = GPIO; \ + (Adapter->LEDInfo.LEDState[index].BitPolarity == 1) ? \ + wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_CLR_REG, &gpio_val, sizeof(gpio_val)) : \ + wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_SET_REG, &gpio_val, sizeof(gpio_val)); \ + } while (0) + +enum bcm_led_colors { + RED_LED = 1, + BLUE_LED = 2, + YELLOW_LED = 3, + GREEN_LED = 4 +}; + +enum bcm_led_events { + SHUTDOWN_EXIT = 0x00, + DRIVER_INIT = 0x1, + FW_DOWNLOAD = 0x2, + FW_DOWNLOAD_DONE = 0x4, + NO_NETWORK_ENTRY = 0x8, + NORMAL_OPERATION = 0x10, + LOWPOWER_MODE_ENTER = 0x20, + IDLEMODE_CONTINUE = 0x40, + IDLEMODE_EXIT = 0x80, + LED_THREAD_INACTIVE = 0x100, /* Makes the LED thread Inactivce. It wil be equivallent to putting the thread on hold. */ + LED_THREAD_ACTIVE = 0x200, /* Makes the LED Thread Active back. */ + DRIVER_HALT = 0xff +}; /* Enumerated values of different driver states */ + +/* + * Structure which stores the information of different LED types + * and corresponding LED state information of driver states + */ +struct bcm_led_state_info { + unsigned char LED_Type; /* specify GPIO number - use 0xFF if not used */ + unsigned char LED_On_State; /* Bits set or reset for different states */ + unsigned char LED_Blink_State; /* Bits set or reset for blinking LEDs for different states */ + unsigned char GPIO_Num; + unsigned char BitPolarity; /* To represent whether H/W is normal polarity or reverse polarity */ +}; + +struct bcm_led_info { + struct bcm_led_state_info LEDState[NUM_OF_LEDS]; + bool bIdleMode_tx_from_host; /* Variable to notify whether driver came out from idlemode due to Host or target */ + bool bIdle_led_off; + wait_queue_head_t notify_led_event; + wait_queue_head_t idleModeSyncEvent; + struct task_struct *led_cntrl_threadid; + int led_thread_running; + bool bLedInitDone; +}; + +/* LED Thread state. */ +#define BCM_LED_THREAD_DISABLED 0 /* LED Thread is not running. */ +#define BCM_LED_THREAD_RUNNING_ACTIVELY 1 /* LED thread is running. */ +#define BCM_LED_THREAD_RUNNING_INACTIVELY 2 /* LED thread has been put on hold */ + +#endif diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c new file mode 100644 index 00000000000..63be3be62eb --- /dev/null +++ b/drivers/staging/bcm/nvm.c @@ -0,0 +1,4613 @@ +#include "headers.h" + +#define DWORD unsigned int + +static int BcmDoChipSelect(struct bcm_mini_adapter *Adapter, unsigned int offset); +static int BcmGetActiveDSD(struct bcm_mini_adapter *Adapter); +static int BcmGetActiveISO(struct bcm_mini_adapter *Adapter); +static unsigned int BcmGetEEPROMSize(struct bcm_mini_adapter *Adapter); +static int BcmGetFlashCSInfo(struct bcm_mini_adapter *Adapter); +static unsigned int BcmGetFlashSectorSize(struct bcm_mini_adapter *Adapter, unsigned int FlashSectorSizeSig, unsigned int FlashSectorSize); + +static VOID BcmValidateNvmType(struct bcm_mini_adapter *Adapter); +static int BcmGetNvmSize(struct bcm_mini_adapter *Adapter); +static unsigned int BcmGetFlashSize(struct bcm_mini_adapter *Adapter); +static enum bcm_nvm_type BcmGetNvmType(struct bcm_mini_adapter *Adapter); + +static int BcmGetSectionValEndOffset(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectionVal); + +static B_UINT8 IsOffsetWritable(struct bcm_mini_adapter *Adapter, unsigned int uiOffset); +static int IsSectionWritable(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val Section); +static int IsSectionExistInVendorInfo(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val section); + +static int ReadDSDPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val dsd); +static int ReadDSDSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val dsd); +static int ReadISOPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val iso); +static int ReadISOSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val iso); + +static int CorruptDSDSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectionVal); +static int CorruptISOSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectionVal); +static int SaveHeaderIfPresent(struct bcm_mini_adapter *Adapter, PUCHAR pBuff, unsigned int uiSectAlignAddr); +static int WriteToFlashWithoutSectorErase(struct bcm_mini_adapter *Adapter, PUINT pBuff, + enum bcm_flash2x_section_val eFlash2xSectionVal, + unsigned int uiOffset, unsigned int uiNumBytes); +static enum bcm_flash2x_section_val getHighestPriDSD(struct bcm_mini_adapter *Adapter); +static enum bcm_flash2x_section_val getHighestPriISO(struct bcm_mini_adapter *Adapter); + +static int BeceemFlashBulkRead( + struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + unsigned int uiOffset, + unsigned int uiNumBytes); + +static int BeceemFlashBulkWrite( + struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + unsigned int uiOffset, + unsigned int uiNumBytes, + bool bVerify); + +static int GetFlashBaseAddr(struct bcm_mini_adapter *Adapter); + +static int ReadBeceemEEPROMBulk(struct bcm_mini_adapter *Adapter, unsigned int dwAddress, unsigned int *pdwData, unsigned int dwNumData); + +/* Procedure: ReadEEPROMStatusRegister + * + * Description: Reads the standard EEPROM Status Register. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * Returns: + * OSAL_STATUS_CODE + */ +static UCHAR ReadEEPROMStatusRegister(struct bcm_mini_adapter *Adapter) +{ + UCHAR uiData = 0; + DWORD dwRetries = MAX_EEPROM_RETRIES * RETRIES_PER_DELAY; + unsigned int uiStatus = 0; + unsigned int value = 0; + unsigned int value1 = 0; + + /* Read the EEPROM status register */ + value = EEPROM_READ_STATUS_REGISTER; + wrmalt(Adapter, EEPROM_CMDQ_SPI_REG, &value, sizeof(value)); + + while (dwRetries != 0) { + value = 0; + uiStatus = 0; + rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &uiStatus, sizeof(uiStatus)); + if (Adapter->device_removed == TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Modem has got removed hence exiting...."); + break; + } + + /* Wait for Avail bit to be set. */ + if ((uiStatus & EEPROM_READ_DATA_AVAIL) != 0) { + /* Clear the Avail/Full bits - which ever is set. */ + value = uiStatus & (EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL); + wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value)); + + value = 0; + rdmalt(Adapter, EEPROM_READ_DATAQ_REG, &value, sizeof(value)); + uiData = (UCHAR)value; + + break; + } + + dwRetries--; + if (dwRetries == 0) { + rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value)); + rdmalt(Adapter, EEPROM_SPI_Q_STATUS_REG, &value1, sizeof(value1)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "0x3004 = %x 0x3008 = %x, retries = %d failed.\n", value, value1, MAX_EEPROM_RETRIES * RETRIES_PER_DELAY); + return uiData; + } + if (!(dwRetries%RETRIES_PER_DELAY)) + udelay(1000); + uiStatus = 0; + } + return uiData; +} /* ReadEEPROMStatusRegister */ + +/* + * Procedure: ReadBeceemEEPROMBulk + * + * Description: This routine reads 16Byte data from EEPROM + * + * Arguments: + * Adapter - ptr to Adapter object instance + * dwAddress - EEPROM Offset to read the data from. + * pdwData - Pointer to double word where data needs to be stored in. // dwNumWords - Number of words. Valid values are 4 ONLY. + * + * Returns: + * OSAL_STATUS_CODE: + */ + +static int ReadBeceemEEPROMBulk(struct bcm_mini_adapter *Adapter, + DWORD dwAddress, + DWORD *pdwData, + DWORD dwNumWords) +{ + DWORD dwIndex = 0; + DWORD dwRetries = MAX_EEPROM_RETRIES * RETRIES_PER_DELAY; + unsigned int uiStatus = 0; + unsigned int value = 0; + unsigned int value1 = 0; + UCHAR *pvalue; + + /* Flush the read and cmd queue. */ + value = (EEPROM_READ_QUEUE_FLUSH | EEPROM_CMD_QUEUE_FLUSH); + wrmalt(Adapter, SPI_FLUSH_REG, &value, sizeof(value)); + value = 0; + wrmalt(Adapter, SPI_FLUSH_REG, &value, sizeof(value)); + + /* Clear the Avail/Full bits. */ + value = (EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL); + wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value)); + + value = dwAddress | ((dwNumWords == 4) ? EEPROM_16_BYTE_PAGE_READ : EEPROM_4_BYTE_PAGE_READ); + wrmalt(Adapter, EEPROM_CMDQ_SPI_REG, &value, sizeof(value)); + + while (dwRetries != 0) { + uiStatus = 0; + rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &uiStatus, sizeof(uiStatus)); + if (Adapter->device_removed == TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Modem has got Removed.hence exiting from loop..."); + return -ENODEV; + } + + /* If we are reading 16 bytes we want to be sure that the queue + * is full before we read. In the other cases we are ok if the + * queue has data available + */ + if (dwNumWords == 4) { + if ((uiStatus & EEPROM_READ_DATA_FULL) != 0) { + /* Clear the Avail/Full bits - which ever is set. */ + value = (uiStatus & (EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL)); + wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value)); + break; + } + } else if (dwNumWords == 1) { + if ((uiStatus & EEPROM_READ_DATA_AVAIL) != 0) { + /* We just got Avail and we have to read 32bits so we + * need this sleep for Cardbus kind of devices. + */ + if (Adapter->chip_id == 0xBECE0210) + udelay(800); + + /* Clear the Avail/Full bits - which ever is set. */ + value = (uiStatus & (EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL)); + wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value)); + break; + } + } + + uiStatus = 0; + + dwRetries--; + if (dwRetries == 0) { + value = 0; + value1 = 0; + rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value)); + rdmalt(Adapter, EEPROM_SPI_Q_STATUS_REG, &value1, sizeof(value1)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "dwNumWords %d 0x3004 = %x 0x3008 = %x retries = %d failed.\n", + dwNumWords, value, value1, MAX_EEPROM_RETRIES * RETRIES_PER_DELAY); + return STATUS_FAILURE; + } + + if (!(dwRetries%RETRIES_PER_DELAY)) + udelay(1000); + } + + for (dwIndex = 0; dwIndex < dwNumWords; dwIndex++) { + /* We get only a byte at a time - from LSB to MSB. We shift it into an integer. */ + pvalue = (PUCHAR)(pdwData + dwIndex); + + value = 0; + rdmalt(Adapter, EEPROM_READ_DATAQ_REG, &value, sizeof(value)); + + pvalue[0] = value; + + value = 0; + rdmalt(Adapter, EEPROM_READ_DATAQ_REG, &value, sizeof(value)); + + pvalue[1] = value; + + value = 0; + rdmalt(Adapter, EEPROM_READ_DATAQ_REG, &value, sizeof(value)); + + pvalue[2] = value; + + value = 0; + rdmalt(Adapter, EEPROM_READ_DATAQ_REG, &value, sizeof(value)); + + pvalue[3] = value; + } + + return STATUS_SUCCESS; +} /* ReadBeceemEEPROMBulk() */ + +/* + * Procedure: ReadBeceemEEPROM + * + * Description: This routine reads 4 data from EEPROM. It uses 1 or 2 page + * reads to do this operation. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * uiOffset - EEPROM Offset to read the data from. + * pBuffer - Pointer to word where data needs to be stored in. + * + * Returns: + * OSAL_STATUS_CODE: + */ + +int ReadBeceemEEPROM(struct bcm_mini_adapter *Adapter, + DWORD uiOffset, + DWORD *pBuffer) +{ + unsigned int uiData[8] = {0}; + unsigned int uiByteOffset = 0; + unsigned int uiTempOffset = 0; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, " ====> "); + + uiTempOffset = uiOffset - (uiOffset % MAX_RW_SIZE); + uiByteOffset = uiOffset - uiTempOffset; + + ReadBeceemEEPROMBulk(Adapter, uiTempOffset, (PUINT)&uiData[0], 4); + + /* A word can overlap at most over 2 pages. In that case we read the + * next page too. + */ + if (uiByteOffset > 12) + ReadBeceemEEPROMBulk(Adapter, uiTempOffset + MAX_RW_SIZE, (PUINT)&uiData[4], 4); + + memcpy((PUCHAR)pBuffer, (((PUCHAR)&uiData[0]) + uiByteOffset), 4); + + return STATUS_SUCCESS; +} /* ReadBeceemEEPROM() */ + +int ReadMacAddressFromNVM(struct bcm_mini_adapter *Adapter) +{ + int Status; + unsigned char puMacAddr[6]; + + Status = BeceemNVMRead(Adapter, + (PUINT)&puMacAddr[0], + INIT_PARAMS_1_MACADDRESS_ADDRESS, + MAC_ADDRESS_SIZE); + + if (Status == STATUS_SUCCESS) + memcpy(Adapter->dev->dev_addr, puMacAddr, MAC_ADDRESS_SIZE); + + return Status; +} + +/* + * Procedure: BeceemEEPROMBulkRead + * + * Description: Reads the EEPROM and returns the Data. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * pBuffer - Buffer to store the data read from EEPROM + * uiOffset - Offset of EEPROM from where data should be read + * uiNumBytes - Number of bytes to be read from the EEPROM. + * + * Returns: + * OSAL_STATUS_SUCCESS - if EEPROM read is successful. + * <FAILURE> - if failed. + */ + +int BeceemEEPROMBulkRead(struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + unsigned int uiOffset, + unsigned int uiNumBytes) +{ + unsigned int uiData[4] = {0}; + /* unsigned int uiAddress = 0; */ + unsigned int uiBytesRemaining = uiNumBytes; + unsigned int uiIndex = 0; + unsigned int uiTempOffset = 0; + unsigned int uiExtraBytes = 0; + unsigned int uiFailureRetries = 0; + PUCHAR pcBuff = (PUCHAR)pBuffer; + + if (uiOffset % MAX_RW_SIZE && uiBytesRemaining) { + uiTempOffset = uiOffset - (uiOffset % MAX_RW_SIZE); + uiExtraBytes = uiOffset - uiTempOffset; + ReadBeceemEEPROMBulk(Adapter, uiTempOffset, (PUINT)&uiData[0], 4); + if (uiBytesRemaining >= (MAX_RW_SIZE - uiExtraBytes)) { + memcpy(pBuffer, (((PUCHAR)&uiData[0]) + uiExtraBytes), MAX_RW_SIZE - uiExtraBytes); + uiBytesRemaining -= (MAX_RW_SIZE - uiExtraBytes); + uiIndex += (MAX_RW_SIZE - uiExtraBytes); + uiOffset += (MAX_RW_SIZE - uiExtraBytes); + } else { + memcpy(pBuffer, (((PUCHAR)&uiData[0]) + uiExtraBytes), uiBytesRemaining); + uiIndex += uiBytesRemaining; + uiOffset += uiBytesRemaining; + uiBytesRemaining = 0; + } + } + + while (uiBytesRemaining && uiFailureRetries != 128) { + if (Adapter->device_removed) + return -1; + + if (uiBytesRemaining >= MAX_RW_SIZE) { + /* For the requests more than or equal to 16 bytes, use bulk + * read function to make the access faster. + * We read 4 Dwords of data + */ + if (ReadBeceemEEPROMBulk(Adapter, uiOffset, &uiData[0], 4) == 0) { + memcpy(pcBuff + uiIndex, &uiData[0], MAX_RW_SIZE); + uiOffset += MAX_RW_SIZE; + uiBytesRemaining -= MAX_RW_SIZE; + uiIndex += MAX_RW_SIZE; + } else { + uiFailureRetries++; + mdelay(3); /* sleep for a while before retry... */ + } + } else if (uiBytesRemaining >= 4) { + if (ReadBeceemEEPROM(Adapter, uiOffset, &uiData[0]) == 0) { + memcpy(pcBuff + uiIndex, &uiData[0], 4); + uiOffset += 4; + uiBytesRemaining -= 4; + uiIndex += 4; + } else { + uiFailureRetries++; + mdelay(3); /* sleep for a while before retry... */ + } + } else { + /* Handle the reads less than 4 bytes... */ + PUCHAR pCharBuff = (PUCHAR)pBuffer; + pCharBuff += uiIndex; + if (ReadBeceemEEPROM(Adapter, uiOffset, &uiData[0]) == 0) { + memcpy(pCharBuff, &uiData[0], uiBytesRemaining); /* copy only bytes requested. */ + uiBytesRemaining = 0; + } else { + uiFailureRetries++; + mdelay(3); /* sleep for a while before retry... */ + } + } + } + + return 0; +} + +/* + * Procedure: BeceemFlashBulkRead + * + * Description: Reads the FLASH and returns the Data. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * pBuffer - Buffer to store the data read from FLASH + * uiOffset - Offset of FLASH from where data should be read + * uiNumBytes - Number of bytes to be read from the FLASH. + * + * Returns: + * OSAL_STATUS_SUCCESS - if FLASH read is successful. + * <FAILURE> - if failed. + */ + +static int BeceemFlashBulkRead(struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + unsigned int uiOffset, + unsigned int uiNumBytes) +{ + unsigned int uiIndex = 0; + unsigned int uiBytesToRead = uiNumBytes; + int Status = 0; + unsigned int uiPartOffset = 0; + int bytes; + + if (Adapter->device_removed) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device Got Removed"); + return -ENODEV; + } + + /* Adding flash Base address + * uiOffset = uiOffset + GetFlashBaseAddr(Adapter); + */ + #if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS) + Status = bcmflash_raw_read((uiOffset/FLASH_PART_SIZE), (uiOffset % FLASH_PART_SIZE), (unsigned char *)pBuffer, uiNumBytes); + return Status; + #endif + + Adapter->SelectedChip = RESET_CHIP_SELECT; + + if (uiOffset % MAX_RW_SIZE) { + BcmDoChipSelect(Adapter, uiOffset); + uiPartOffset = (uiOffset & (FLASH_PART_SIZE - 1)) + GetFlashBaseAddr(Adapter); + + uiBytesToRead = MAX_RW_SIZE - (uiOffset % MAX_RW_SIZE); + uiBytesToRead = MIN(uiNumBytes, uiBytesToRead); + + bytes = rdm(Adapter, uiPartOffset, (PCHAR)pBuffer + uiIndex, uiBytesToRead); + if (bytes < 0) { + Status = bytes; + Adapter->SelectedChip = RESET_CHIP_SELECT; + return Status; + } + + uiIndex += uiBytesToRead; + uiOffset += uiBytesToRead; + uiNumBytes -= uiBytesToRead; + } + + while (uiNumBytes) { + BcmDoChipSelect(Adapter, uiOffset); + uiPartOffset = (uiOffset & (FLASH_PART_SIZE - 1)) + GetFlashBaseAddr(Adapter); + + uiBytesToRead = MIN(uiNumBytes, MAX_RW_SIZE); + + bytes = rdm(Adapter, uiPartOffset, (PCHAR)pBuffer + uiIndex, uiBytesToRead); + if (bytes < 0) { + Status = bytes; + break; + } + + uiIndex += uiBytesToRead; + uiOffset += uiBytesToRead; + uiNumBytes -= uiBytesToRead; + } + Adapter->SelectedChip = RESET_CHIP_SELECT; + return Status; +} + +/* + * Procedure: BcmGetFlashSize + * + * Description: Finds the size of FLASH. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * + * Returns: + * unsigned int - size of the FLASH Storage. + * + */ + +static unsigned int BcmGetFlashSize(struct bcm_mini_adapter *Adapter) +{ + if (IsFlash2x(Adapter)) + return Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(struct bcm_dsd_header); + else + return 32 * 1024; +} + +/* + * Procedure: BcmGetEEPROMSize + * + * Description: Finds the size of EEPROM. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * + * Returns: + * unsigned int - size of the EEPROM Storage. + * + */ + +static unsigned int BcmGetEEPROMSize(struct bcm_mini_adapter *Adapter) +{ + unsigned int uiData = 0; + unsigned int uiIndex = 0; + + /* + * if EEPROM is present and already Calibrated,it will have + * 'BECM' string at 0th offset. + * To find the EEPROM size read the possible boundaries of the + * EEPROM like 4K,8K etc..accessing the EEPROM beyond its size will + * result in wrap around. So when we get the End of the EEPROM we will + * get 'BECM' string which is indeed at offset 0. + */ + BeceemEEPROMBulkRead(Adapter, &uiData, 0x0, 4); + if (uiData == BECM) { + for (uiIndex = 2; uiIndex <= 256; uiIndex *= 2) { + BeceemEEPROMBulkRead(Adapter, &uiData, uiIndex * 1024, 4); + if (uiData == BECM) + return uiIndex * 1024; + } + } else { + /* + * EEPROM may not be present or not programmed + */ + uiData = 0xBABEFACE; + if (BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&uiData, 0, 4, TRUE) == 0) { + uiData = 0; + for (uiIndex = 2; uiIndex <= 256; uiIndex *= 2) { + BeceemEEPROMBulkRead(Adapter, &uiData, uiIndex * 1024, 4); + if (uiData == 0xBABEFACE) + return uiIndex * 1024; + } + } + } + return 0; +} + +/* + * Procedure: FlashSectorErase + * + * Description: Finds the sector size of the FLASH. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * addr - sector start address + * numOfSectors - number of sectors to be erased. + * + * Returns: + * OSAL_STATUS_CODE + * + */ + +static int FlashSectorErase(struct bcm_mini_adapter *Adapter, + unsigned int addr, + unsigned int numOfSectors) +{ + unsigned int iIndex = 0, iRetries = 0; + unsigned int uiStatus = 0; + unsigned int value; + int bytes; + + for (iIndex = 0; iIndex < numOfSectors; iIndex++) { + value = 0x06000000; + wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)); + + value = (0xd8000000 | (addr & 0xFFFFFF)); + wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)); + iRetries = 0; + + do { + value = (FLASH_CMD_STATUS_REG_READ << 24); + if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programing of FLASH_SPI_CMDQ_REG fails"); + return STATUS_FAILURE; + } + + bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)); + if (bytes < 0) { + uiStatus = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reading status of FLASH_SPI_READQ_REG fails"); + return uiStatus; + } + iRetries++; + /* After every try lets make the CPU free for 10 ms. generally time taken by the + * the sector erase cycle is 500 ms to 40000 msec. hence sleeping 10 ms + * won't hamper performance in any case. + */ + mdelay(10); + } while ((uiStatus & 0x1) && (iRetries < 400)); + + if (uiStatus & 0x1) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "iRetries crossing the limit of 80000\n"); + return STATUS_FAILURE; + } + + addr += Adapter->uiSectorSize; + } + return 0; +} +/* + * Procedure: flashByteWrite + * + * Description: Performs Byte by Byte write to flash + * + * Arguments: + * Adapter - ptr to Adapter object instance + * uiOffset - Offset of the flash where data needs to be written to. + * pData - Address of Data to be written. + * Returns: + * OSAL_STATUS_CODE + * + */ + +static int flashByteWrite(struct bcm_mini_adapter *Adapter, + unsigned int uiOffset, + PVOID pData) +{ + unsigned int uiStatus = 0; + int iRetries = MAX_FLASH_RETRIES * FLASH_PER_RETRIES_DELAY; /* 3 */ + unsigned int value; + ULONG ulData = *(PUCHAR)pData; + int bytes; + /* + * need not write 0xFF because write requires an erase and erase will + * make whole sector 0xFF. + */ + + if (0xFF == ulData) + return STATUS_SUCCESS; + + /* DumpDebug(NVM_RW,("flashWrite ====>\n")); */ + value = (FLASH_CMD_WRITE_ENABLE << 24); + if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write enable in FLASH_SPI_CMDQ_REG register fails"); + return STATUS_FAILURE; + } + + if (wrm(Adapter, FLASH_SPI_WRITEQ_REG, (PCHAR)&ulData, 4) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "DATA Write on FLASH_SPI_WRITEQ_REG fails"); + return STATUS_FAILURE; + } + value = (0x02000000 | (uiOffset & 0xFFFFFF)); + if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programming of FLASH_SPI_CMDQ_REG fails"); + return STATUS_FAILURE; + } + + /* __udelay(950); */ + + do { + value = (FLASH_CMD_STATUS_REG_READ << 24); + if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programing of FLASH_SPI_CMDQ_REG fails"); + return STATUS_FAILURE; + } + /* __udelay(1); */ + bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)); + if (bytes < 0) { + uiStatus = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reading status of FLASH_SPI_READQ_REG fails"); + return uiStatus; + } + iRetries--; + if (iRetries && ((iRetries % FLASH_PER_RETRIES_DELAY) == 0)) + udelay(1000); + + } while ((uiStatus & 0x1) && (iRetries > 0)); + + if (uiStatus & 0x1) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Write fails even after checking status for 200 times."); + return STATUS_FAILURE; + } + + return STATUS_SUCCESS; +} + +/* + * Procedure: flashWrite + * + * Description: Performs write to flash + * + * Arguments: + * Adapter - ptr to Adapter object instance + * uiOffset - Offset of the flash where data needs to be written to. + * pData - Address of Data to be written. + * Returns: + * OSAL_STATUS_CODE + * + */ + +static int flashWrite(struct bcm_mini_adapter *Adapter, + unsigned int uiOffset, + PVOID pData) +{ + /* unsigned int uiStatus = 0; + * int iRetries = 0; + * unsigned int uiReadBack = 0; + */ + unsigned int uiStatus = 0; + int iRetries = MAX_FLASH_RETRIES * FLASH_PER_RETRIES_DELAY; /* 3 */ + unsigned int value; + unsigned int uiErasePattern[4] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}; + int bytes; + /* + * need not write 0xFFFFFFFF because write requires an erase and erase will + * make whole sector 0xFFFFFFFF. + */ + if (!memcmp(pData, uiErasePattern, MAX_RW_SIZE)) + return 0; + + value = (FLASH_CMD_WRITE_ENABLE << 24); + + if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write Enable of FLASH_SPI_CMDQ_REG fails"); + return STATUS_FAILURE; + } + + if (wrm(Adapter, uiOffset, (PCHAR)pData, MAX_RW_SIZE) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Data write fails..."); + return STATUS_FAILURE; + } + + /* __udelay(950); */ + do { + value = (FLASH_CMD_STATUS_REG_READ << 24); + if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programing of FLASH_SPI_CMDQ_REG fails"); + return STATUS_FAILURE; + } + /* __udelay(1); */ + bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)); + if (bytes < 0) { + uiStatus = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reading status of FLASH_SPI_READQ_REG fails"); + return uiStatus; + } + + iRetries--; + /* this will ensure that in there will be no changes in the current path. + * currently one rdm/wrm takes 125 us. + * Hence 125 *2 * FLASH_PER_RETRIES_DELAY > 3 ms(worst case delay) + * Hence current implementation cycle will intoduce no delay in current path + */ + if (iRetries && ((iRetries % FLASH_PER_RETRIES_DELAY) == 0)) + udelay(1000); + } while ((uiStatus & 0x1) && (iRetries > 0)); + + if (uiStatus & 0x1) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Write fails even after checking status for 200 times."); + return STATUS_FAILURE; + } + + return STATUS_SUCCESS; +} + +/*----------------------------------------------------------------------------- + * Procedure: flashByteWriteStatus + * + * Description: Performs byte by byte write to flash with write done status check + * + * Arguments: + * Adapter - ptr to Adapter object instance + * uiOffset - Offset of the flash where data needs to be written to. + * pData - Address of the Data to be written. + * Returns: + * OSAL_STATUS_CODE + * + */ +static int flashByteWriteStatus(struct bcm_mini_adapter *Adapter, + unsigned int uiOffset, + PVOID pData) +{ + unsigned int uiStatus = 0; + int iRetries = MAX_FLASH_RETRIES * FLASH_PER_RETRIES_DELAY; /* 3 */ + ULONG ulData = *(PUCHAR)pData; + unsigned int value; + int bytes; + + /* + * need not write 0xFFFFFFFF because write requires an erase and erase will + * make whole sector 0xFFFFFFFF. + */ + + if (0xFF == ulData) + return STATUS_SUCCESS; + + /* DumpDebug(NVM_RW,("flashWrite ====>\n")); */ + + value = (FLASH_CMD_WRITE_ENABLE << 24); + if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write enable in FLASH_SPI_CMDQ_REG register fails"); + return STATUS_SUCCESS; + } + if (wrm(Adapter, FLASH_SPI_WRITEQ_REG, (PCHAR)&ulData, 4) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "DATA Write on FLASH_SPI_WRITEQ_REG fails"); + return STATUS_FAILURE; + } + value = (0x02000000 | (uiOffset & 0xFFFFFF)); + if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programming of FLASH_SPI_CMDQ_REG fails"); + return STATUS_FAILURE; + } + + /* msleep(1); */ + + do { + value = (FLASH_CMD_STATUS_REG_READ << 24); + if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programing of FLASH_SPI_CMDQ_REG fails"); + return STATUS_FAILURE; + } + /* __udelay(1); */ + bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)); + if (bytes < 0) { + uiStatus = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reading status of FLASH_SPI_READQ_REG fails"); + return uiStatus; + } + + iRetries--; + if (iRetries && ((iRetries % FLASH_PER_RETRIES_DELAY) == 0)) + udelay(1000); + + } while ((uiStatus & 0x1) && (iRetries > 0)); + + if (uiStatus & 0x1) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Write fails even after checking status for 200 times."); + return STATUS_FAILURE; + } + + return STATUS_SUCCESS; +} +/* + * Procedure: flashWriteStatus + * + * Description: Performs write to flash with write done status check + * + * Arguments: + * Adapter - ptr to Adapter object instance + * uiOffset - Offset of the flash where data needs to be written to. + * pData - Address of the Data to be written. + * Returns: + * OSAL_STATUS_CODE + * + */ + +static int flashWriteStatus(struct bcm_mini_adapter *Adapter, + unsigned int uiOffset, + PVOID pData) +{ + unsigned int uiStatus = 0; + int iRetries = MAX_FLASH_RETRIES * FLASH_PER_RETRIES_DELAY; /* 3 */ + /* unsigned int uiReadBack = 0; */ + unsigned int value; + unsigned int uiErasePattern[4] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}; + int bytes; + + /* + * need not write 0xFFFFFFFF because write requires an erase and erase will + * make whole sector 0xFFFFFFFF. + */ + if (!memcmp(pData, uiErasePattern, MAX_RW_SIZE)) + return 0; + + value = (FLASH_CMD_WRITE_ENABLE << 24); + if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write Enable of FLASH_SPI_CMDQ_REG fails"); + return STATUS_FAILURE; + } + + if (wrm(Adapter, uiOffset, (PCHAR)pData, MAX_RW_SIZE) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Data write fails..."); + return STATUS_FAILURE; + } + /* __udelay(1); */ + + do { + value = (FLASH_CMD_STATUS_REG_READ << 24); + if (wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)) < 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Programing of FLASH_SPI_CMDQ_REG fails"); + return STATUS_FAILURE; + } + /* __udelay(1); */ + bytes = rdmalt(Adapter, FLASH_SPI_READQ_REG, &uiStatus, sizeof(uiStatus)); + if (bytes < 0) { + uiStatus = bytes; + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Reading status of FLASH_SPI_READQ_REG fails"); + return uiStatus; + } + iRetries--; + /* this will ensure that in there will be no changes in the current path. + * currently one rdm/wrm takes 125 us. + * Hence 125 *2 * FLASH_PER_RETRIES_DELAY >3 ms(worst case delay) + * Hence current implementation cycle will intoduce no delay in current path + */ + if (iRetries && ((iRetries % FLASH_PER_RETRIES_DELAY) == 0)) + udelay(1000); + + } while ((uiStatus & 0x1) && (iRetries > 0)); + + if (uiStatus & 0x1) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Write fails even after checking status for 200 times."); + return STATUS_FAILURE; + } + + return STATUS_SUCCESS; +} + +/* + * Procedure: BcmRestoreBlockProtectStatus + * + * Description: Restores the original block protection status. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * ulWriteStatus -Original status + * Returns: + * <VOID> + * + */ + +static VOID BcmRestoreBlockProtectStatus(struct bcm_mini_adapter *Adapter, ULONG ulWriteStatus) +{ + unsigned int value; + value = (FLASH_CMD_WRITE_ENABLE << 24); + wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)); + + udelay(20); + value = (FLASH_CMD_STATUS_REG_WRITE << 24) | (ulWriteStatus << 16); + wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)); + udelay(20); +} + +/* + * Procedure: BcmFlashUnProtectBlock + * + * Description: UnProtects appropriate blocks for writing. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * uiOffset - Offset of the flash where data needs to be written to. This should be Sector aligned. + * Returns: + * ULONG - Status value before UnProtect. + * + */ + +static ULONG BcmFlashUnProtectBlock(struct bcm_mini_adapter *Adapter, unsigned int uiOffset, unsigned int uiLength) +{ + ULONG ulStatus = 0; + ULONG ulWriteStatus = 0; + unsigned int value; + + uiOffset = uiOffset&0x000FFFFF; + /* + * Implemented only for 1MB Flash parts. + */ + if (FLASH_PART_SST25VF080B == Adapter->ulFlashID) { + /* + * Get Current BP status. + */ + value = (FLASH_CMD_STATUS_REG_READ << 24); + wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)); + udelay(10); + /* + * Read status will be WWXXYYZZ. We have to take only WW. + */ + rdmalt(Adapter, FLASH_SPI_READQ_REG, (PUINT)&ulStatus, sizeof(ulStatus)); + ulStatus >>= 24; + ulWriteStatus = ulStatus; + /* + * Bits [5-2] give current block level protection status. + * Bit5: BP3 - DONT CARE + * BP2-BP0: 0 - NO PROTECTION, 1 - UPPER 1/16, 2 - UPPER 1/8, 3 - UPPER 1/4 + * 4 - UPPER 1/2. 5 to 7 - ALL BLOCKS + */ + + if (ulStatus) { + if ((uiOffset+uiLength) <= 0x80000) { + /* + * Offset comes in lower half of 1MB. Protect the upper half. + * Clear BP1 and BP0 and set BP2. + */ + ulWriteStatus |= (0x4<<2); + ulWriteStatus &= ~(0x3<<2); + } else if ((uiOffset + uiLength) <= 0xC0000) { + /* + * Offset comes below Upper 1/4. Upper 1/4 can be protected. + * Clear BP2 and set BP1 and BP0. + */ + ulWriteStatus |= (0x3<<2); + ulWriteStatus &= ~(0x1<<4); + } else if ((uiOffset + uiLength) <= 0xE0000) { + /* + * Offset comes below Upper 1/8. Upper 1/8 can be protected. + * Clear BP2 and BP0 and set BP1 + */ + ulWriteStatus |= (0x1<<3); + ulWriteStatus &= ~(0x5<<2); + } else if ((uiOffset + uiLength) <= 0xF0000) { + /* + * Offset comes below Upper 1/16. Only upper 1/16 can be protected. + * Set BP0 and Clear BP2,BP1. + */ + ulWriteStatus |= (0x1<<2); + ulWriteStatus &= ~(0x3<<3); + } else { + /* + * Unblock all. + * Clear BP2,BP1 and BP0. + */ + ulWriteStatus &= ~(0x7<<2); + } + + value = (FLASH_CMD_WRITE_ENABLE << 24); + wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)); + udelay(20); + value = (FLASH_CMD_STATUS_REG_WRITE << 24) | (ulWriteStatus << 16); + wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)); + udelay(20); + } + } + return ulStatus; +} + +/* + * Procedure: BeceemFlashBulkWrite + * + * Description: Performs write to the flash + * + * Arguments: + * Adapter - ptr to Adapter object instance + * pBuffer - Data to be written. + * uiOffset - Offset of the flash where data needs to be written to. + * uiNumBytes - Number of bytes to be written. + * bVerify - read verify flag. + * Returns: + * OSAL_STATUS_CODE + * + */ + +static int BeceemFlashBulkWrite(struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + unsigned int uiOffset, + unsigned int uiNumBytes, + bool bVerify) +{ + PCHAR pTempBuff = NULL; + PUCHAR pcBuffer = (PUCHAR)pBuffer; + unsigned int uiIndex = 0; + unsigned int uiOffsetFromSectStart = 0; + unsigned int uiSectAlignAddr = 0; + unsigned int uiCurrSectOffsetAddr = 0; + unsigned int uiSectBoundary = 0; + unsigned int uiNumSectTobeRead = 0; + UCHAR ucReadBk[16] = {0}; + ULONG ulStatus = 0; + int Status = STATUS_SUCCESS; + unsigned int uiTemp = 0; + unsigned int index = 0; + unsigned int uiPartOffset = 0; + + #if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS) + Status = bcmflash_raw_write((uiOffset / FLASH_PART_SIZE), (uiOffset % FLASH_PART_SIZE), (unsigned char *)pBuffer, uiNumBytes); + return Status; + #endif + + uiOffsetFromSectStart = uiOffset & ~(Adapter->uiSectorSize - 1); + + /* Adding flash Base address + * uiOffset = uiOffset + GetFlashBaseAddr(Adapter); + */ + + uiSectAlignAddr = uiOffset & ~(Adapter->uiSectorSize - 1); + uiCurrSectOffsetAddr = uiOffset & (Adapter->uiSectorSize - 1); + uiSectBoundary = uiSectAlignAddr + Adapter->uiSectorSize; + + pTempBuff = kmalloc(Adapter->uiSectorSize, GFP_KERNEL); + if (!pTempBuff) + goto BeceemFlashBulkWrite_EXIT; + /* + * check if the data to be written is overlapped across sectors + */ + if (uiOffset+uiNumBytes < uiSectBoundary) { + uiNumSectTobeRead = 1; + } else { + /* Number of sectors = Last sector start address/First sector start address */ + uiNumSectTobeRead = (uiCurrSectOffsetAddr + uiNumBytes) / Adapter->uiSectorSize; + if ((uiCurrSectOffsetAddr + uiNumBytes)%Adapter->uiSectorSize) + uiNumSectTobeRead++; + } + /* Check whether Requested sector is writable or not in case of flash2x write. But if write call is + * for DSD calibration, allow it without checking of sector permission + */ + + if (IsFlash2x(Adapter) && (Adapter->bAllDSDWriteAllow == false)) { + index = 0; + uiTemp = uiNumSectTobeRead; + while (uiTemp) { + if (IsOffsetWritable(Adapter, uiOffsetFromSectStart + index * Adapter->uiSectorSize) == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Sector Starting at offset <0X%X> is not writable", + (uiOffsetFromSectStart + index * Adapter->uiSectorSize)); + Status = SECTOR_IS_NOT_WRITABLE; + goto BeceemFlashBulkWrite_EXIT; + } + uiTemp = uiTemp - 1; + index = index + 1; + } + } + Adapter->SelectedChip = RESET_CHIP_SELECT; + while (uiNumSectTobeRead) { + /* do_gettimeofday(&tv1); + * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "\nTime In start of write :%ld ms\n",(tv1.tv_sec *1000 + tv1.tv_usec /1000)); + */ + uiPartOffset = (uiSectAlignAddr & (FLASH_PART_SIZE - 1)) + GetFlashBaseAddr(Adapter); + + BcmDoChipSelect(Adapter, uiSectAlignAddr); + + if (0 != BeceemFlashBulkRead(Adapter, + (PUINT)pTempBuff, + uiOffsetFromSectStart, + Adapter->uiSectorSize)) { + Status = -1; + goto BeceemFlashBulkWrite_EXIT; + } + + /* do_gettimeofday(&tr); + * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken by Read :%ld ms\n", (tr.tv_sec *1000 + tr.tv_usec/1000) - (tv1.tv_sec *1000 + tv1.tv_usec/1000)); + */ + ulStatus = BcmFlashUnProtectBlock(Adapter, uiSectAlignAddr, Adapter->uiSectorSize); + + if (uiNumSectTobeRead > 1) { + memcpy(&pTempBuff[uiCurrSectOffsetAddr], pcBuffer, uiSectBoundary - (uiSectAlignAddr + uiCurrSectOffsetAddr)); + pcBuffer += ((uiSectBoundary - (uiSectAlignAddr + uiCurrSectOffsetAddr))); + uiNumBytes -= (uiSectBoundary - (uiSectAlignAddr + uiCurrSectOffsetAddr)); + } else { + memcpy(&pTempBuff[uiCurrSectOffsetAddr], pcBuffer, uiNumBytes); + } + + if (IsFlash2x(Adapter)) + SaveHeaderIfPresent(Adapter, (PUCHAR)pTempBuff, uiOffsetFromSectStart); + + FlashSectorErase(Adapter, uiPartOffset, 1); + /* do_gettimeofday(&te); + * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken by Erase :%ld ms\n", (te.tv_sec *1000 + te.tv_usec/1000) - (tr.tv_sec *1000 + tr.tv_usec/1000)); + */ + for (uiIndex = 0; uiIndex < Adapter->uiSectorSize; uiIndex += Adapter->ulFlashWriteSize) { + if (Adapter->device_removed) { + Status = -1; + goto BeceemFlashBulkWrite_EXIT; + } + + if (STATUS_SUCCESS != (*Adapter->fpFlashWrite)(Adapter, uiPartOffset + uiIndex, (&pTempBuff[uiIndex]))) { + Status = -1; + goto BeceemFlashBulkWrite_EXIT; + } + } + + /* do_gettimeofday(&tw); + * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken in Write to Flash :%ld ms\n", (tw.tv_sec *1000 + tw.tv_usec/1000) - (te.tv_sec *1000 + te.tv_usec/1000)); + */ + for (uiIndex = 0; uiIndex < Adapter->uiSectorSize; uiIndex += MAX_RW_SIZE) { + if (STATUS_SUCCESS == BeceemFlashBulkRead(Adapter, (PUINT)ucReadBk, uiOffsetFromSectStart + uiIndex, MAX_RW_SIZE)) { + if (Adapter->ulFlashWriteSize == 1) { + unsigned int uiReadIndex = 0; + for (uiReadIndex = 0; uiReadIndex < 16; uiReadIndex++) { + if (ucReadBk[uiReadIndex] != pTempBuff[uiIndex + uiReadIndex]) { + if (STATUS_SUCCESS != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter, uiPartOffset + uiIndex + uiReadIndex, &pTempBuff[uiIndex+uiReadIndex])) { + Status = STATUS_FAILURE; + goto BeceemFlashBulkWrite_EXIT; + } + } + } + } else { + if (memcmp(ucReadBk, &pTempBuff[uiIndex], MAX_RW_SIZE)) { + if (STATUS_SUCCESS != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter, uiPartOffset + uiIndex, &pTempBuff[uiIndex])) { + Status = STATUS_FAILURE; + goto BeceemFlashBulkWrite_EXIT; + } + } + } + } + } + /* do_gettimeofday(&twv); + * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken in Write to Flash verification :%ld ms\n", (twv.tv_sec *1000 + twv.tv_usec/1000) - (tw.tv_sec *1000 + tw.tv_usec/1000)); + */ + if (ulStatus) { + BcmRestoreBlockProtectStatus(Adapter, ulStatus); + ulStatus = 0; + } + + uiCurrSectOffsetAddr = 0; + uiSectAlignAddr = uiSectBoundary; + uiSectBoundary += Adapter->uiSectorSize; + uiOffsetFromSectStart += Adapter->uiSectorSize; + uiNumSectTobeRead--; + } + /* do_gettimeofday(&tv2); + * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Time after Write :%ld ms\n",(tv2.tv_sec *1000 + tv2.tv_usec/1000)); + * BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0, "Total time taken by in Write is :%ld ms\n", (tv2.tv_sec *1000 + tv2.tv_usec/1000) - (tv1.tv_sec *1000 + tv1.tv_usec/1000)); + * + * Cleanup. + */ +BeceemFlashBulkWrite_EXIT: + if (ulStatus) + BcmRestoreBlockProtectStatus(Adapter, ulStatus); + + kfree(pTempBuff); + + Adapter->SelectedChip = RESET_CHIP_SELECT; + return Status; +} + +/* + * Procedure: BeceemFlashBulkWriteStatus + * + * Description: Writes to Flash. Checks the SPI status after each write. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * pBuffer - Data to be written. + * uiOffset - Offset of the flash where data needs to be written to. + * uiNumBytes - Number of bytes to be written. + * bVerify - read verify flag. + * Returns: + * OSAL_STATUS_CODE + * + */ + +static int BeceemFlashBulkWriteStatus(struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + unsigned int uiOffset, + unsigned int uiNumBytes, + bool bVerify) +{ + PCHAR pTempBuff = NULL; + PUCHAR pcBuffer = (PUCHAR)pBuffer; + unsigned int uiIndex = 0; + unsigned int uiOffsetFromSectStart = 0; + unsigned int uiSectAlignAddr = 0; + unsigned int uiCurrSectOffsetAddr = 0; + unsigned int uiSectBoundary = 0; + unsigned int uiNumSectTobeRead = 0; + UCHAR ucReadBk[16] = {0}; + ULONG ulStatus = 0; + unsigned int Status = STATUS_SUCCESS; + unsigned int uiTemp = 0; + unsigned int index = 0; + unsigned int uiPartOffset = 0; + + uiOffsetFromSectStart = uiOffset & ~(Adapter->uiSectorSize - 1); + + /* uiOffset += Adapter->ulFlashCalStart; + * Adding flash Base address + * uiOffset = uiOffset + GetFlashBaseAddr(Adapter); + */ + uiSectAlignAddr = uiOffset & ~(Adapter->uiSectorSize - 1); + uiCurrSectOffsetAddr = uiOffset & (Adapter->uiSectorSize - 1); + uiSectBoundary = uiSectAlignAddr + Adapter->uiSectorSize; + + pTempBuff = kmalloc(Adapter->uiSectorSize, GFP_KERNEL); + if (!pTempBuff) + goto BeceemFlashBulkWriteStatus_EXIT; + + /* + * check if the data to be written is overlapped across sectors + */ + if (uiOffset+uiNumBytes < uiSectBoundary) { + uiNumSectTobeRead = 1; + } else { + /* Number of sectors = Last sector start address/First sector start address */ + uiNumSectTobeRead = (uiCurrSectOffsetAddr + uiNumBytes) / Adapter->uiSectorSize; + if ((uiCurrSectOffsetAddr + uiNumBytes)%Adapter->uiSectorSize) + uiNumSectTobeRead++; + } + + if (IsFlash2x(Adapter) && (Adapter->bAllDSDWriteAllow == false)) { + index = 0; + uiTemp = uiNumSectTobeRead; + while (uiTemp) { + if (IsOffsetWritable(Adapter, uiOffsetFromSectStart + index * Adapter->uiSectorSize) == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Sector Starting at offset <0X%x> is not writable", + (uiOffsetFromSectStart + index * Adapter->uiSectorSize)); + Status = SECTOR_IS_NOT_WRITABLE; + goto BeceemFlashBulkWriteStatus_EXIT; + } + uiTemp = uiTemp - 1; + index = index + 1; + } + } + + Adapter->SelectedChip = RESET_CHIP_SELECT; + while (uiNumSectTobeRead) { + uiPartOffset = (uiSectAlignAddr & (FLASH_PART_SIZE - 1)) + GetFlashBaseAddr(Adapter); + + BcmDoChipSelect(Adapter, uiSectAlignAddr); + if (0 != BeceemFlashBulkRead(Adapter, + (PUINT)pTempBuff, + uiOffsetFromSectStart, + Adapter->uiSectorSize)) { + Status = -1; + goto BeceemFlashBulkWriteStatus_EXIT; + } + + ulStatus = BcmFlashUnProtectBlock(Adapter, uiOffsetFromSectStart, Adapter->uiSectorSize); + + if (uiNumSectTobeRead > 1) { + memcpy(&pTempBuff[uiCurrSectOffsetAddr], pcBuffer, uiSectBoundary - (uiSectAlignAddr + uiCurrSectOffsetAddr)); + pcBuffer += ((uiSectBoundary - (uiSectAlignAddr + uiCurrSectOffsetAddr))); + uiNumBytes -= (uiSectBoundary - (uiSectAlignAddr + uiCurrSectOffsetAddr)); + } else { + memcpy(&pTempBuff[uiCurrSectOffsetAddr], pcBuffer, uiNumBytes); + } + + if (IsFlash2x(Adapter)) + SaveHeaderIfPresent(Adapter, (PUCHAR)pTempBuff, uiOffsetFromSectStart); + + FlashSectorErase(Adapter, uiPartOffset, 1); + + for (uiIndex = 0; uiIndex < Adapter->uiSectorSize; uiIndex += Adapter->ulFlashWriteSize) { + if (Adapter->device_removed) { + Status = -1; + goto BeceemFlashBulkWriteStatus_EXIT; + } + + if (STATUS_SUCCESS != (*Adapter->fpFlashWriteWithStatusCheck)(Adapter, uiPartOffset+uiIndex, &pTempBuff[uiIndex])) { + Status = -1; + goto BeceemFlashBulkWriteStatus_EXIT; + } + } + + if (bVerify) { + for (uiIndex = 0; uiIndex < Adapter->uiSectorSize; uiIndex += MAX_RW_SIZE) { + if (STATUS_SUCCESS == BeceemFlashBulkRead(Adapter, (PUINT)ucReadBk, uiOffsetFromSectStart + uiIndex, MAX_RW_SIZE)) { + if (memcmp(ucReadBk, &pTempBuff[uiIndex], MAX_RW_SIZE)) { + Status = STATUS_FAILURE; + goto BeceemFlashBulkWriteStatus_EXIT; + } + } + } + } + + if (ulStatus) { + BcmRestoreBlockProtectStatus(Adapter, ulStatus); + ulStatus = 0; + } + + uiCurrSectOffsetAddr = 0; + uiSectAlignAddr = uiSectBoundary; + uiSectBoundary += Adapter->uiSectorSize; + uiOffsetFromSectStart += Adapter->uiSectorSize; + uiNumSectTobeRead--; + } +/* + * Cleanup. + */ +BeceemFlashBulkWriteStatus_EXIT: + if (ulStatus) + BcmRestoreBlockProtectStatus(Adapter, ulStatus); + + kfree(pTempBuff); + Adapter->SelectedChip = RESET_CHIP_SELECT; + return Status; +} + +/* + * Procedure: PropagateCalParamsFromFlashToMemory + * + * Description: Dumps the calibration section of EEPROM to DDR. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * Returns: + * OSAL_STATUS_CODE + * + */ + +int PropagateCalParamsFromFlashToMemory(struct bcm_mini_adapter *Adapter) +{ + PCHAR pBuff, pPtr; + unsigned int uiEepromSize = 0; + unsigned int uiBytesToCopy = 0; + /* unsigned int uiIndex = 0; */ + unsigned int uiCalStartAddr = EEPROM_CALPARAM_START; + unsigned int uiMemoryLoc = EEPROM_CAL_DATA_INTERNAL_LOC; + unsigned int value; + int Status = 0; + + /* + * Write the signature first. This will ensure firmware does not access EEPROM. + */ + value = 0xbeadbead; + wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 4, &value, sizeof(value)); + value = 0xbeadbead; + wrmalt(Adapter, EEPROM_CAL_DATA_INTERNAL_LOC - 8, &value, sizeof(value)); + + if (0 != BeceemNVMRead(Adapter, &uiEepromSize, EEPROM_SIZE_OFFSET, 4)) + return -1; + + uiEepromSize = ntohl(uiEepromSize); + uiEepromSize >>= 16; + + /* + * subtract the auto init section size + */ + uiEepromSize -= EEPROM_CALPARAM_START; + + if (uiEepromSize > 1024 * 1024) + return -1; + + pBuff = kmalloc(uiEepromSize, GFP_KERNEL); + if (pBuff == NULL) + return -ENOMEM; + + if (0 != BeceemNVMRead(Adapter, (PUINT)pBuff, uiCalStartAddr, uiEepromSize)) { + kfree(pBuff); + return -1; + } + + pPtr = pBuff; + + uiBytesToCopy = MIN(BUFFER_4K, uiEepromSize); + + while (uiBytesToCopy) { + Status = wrm(Adapter, uiMemoryLoc, (PCHAR)pPtr, uiBytesToCopy); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "wrm failed with status :%d", Status); + break; + } + + pPtr += uiBytesToCopy; + uiEepromSize -= uiBytesToCopy; + uiMemoryLoc += uiBytesToCopy; + uiBytesToCopy = MIN(BUFFER_4K, uiEepromSize); + } + + kfree(pBuff); + return Status; +} + +/* + * Procedure: BeceemEEPROMReadBackandVerify + * + * Description: Read back the data written and verifies. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * pBuffer - Data to be written. + * uiOffset - Offset of the flash where data needs to be written to. + * uiNumBytes - Number of bytes to be written. + * Returns: + * OSAL_STATUS_CODE + * + */ + +static int BeceemEEPROMReadBackandVerify(struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + unsigned int uiOffset, + unsigned int uiNumBytes) +{ + unsigned int uiRdbk = 0; + unsigned int uiIndex = 0; + unsigned int uiData = 0; + unsigned int auiData[4] = {0}; + + while (uiNumBytes) { + if (Adapter->device_removed) + return -1; + + if (uiNumBytes >= MAX_RW_SIZE) { + /* for the requests more than or equal to MAX_RW_SIZE bytes, use bulk read function to make the access faster. */ + BeceemEEPROMBulkRead(Adapter, &auiData[0], uiOffset, MAX_RW_SIZE); + + if (memcmp(&pBuffer[uiIndex], &auiData[0], MAX_RW_SIZE)) { + /* re-write */ + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)(pBuffer + uiIndex), uiOffset, MAX_RW_SIZE, false); + mdelay(3); + BeceemEEPROMBulkRead(Adapter, &auiData[0], uiOffset, MAX_RW_SIZE); + + if (memcmp(&pBuffer[uiIndex], &auiData[0], MAX_RW_SIZE)) + return -1; + } + uiOffset += MAX_RW_SIZE; + uiNumBytes -= MAX_RW_SIZE; + uiIndex += 4; + } else if (uiNumBytes >= 4) { + BeceemEEPROMBulkRead(Adapter, &uiData, uiOffset, 4); + if (uiData != pBuffer[uiIndex]) { + /* re-write */ + BeceemEEPROMBulkWrite(Adapter, (PUCHAR)(pBuffer + uiIndex), uiOffset, 4, false); + mdelay(3); + BeceemEEPROMBulkRead(Adapter, &uiData, uiOffset, 4); + if (uiData != pBuffer[uiIndex]) + return -1; + } + uiOffset += 4; + uiNumBytes -= 4; + uiIndex++; + } else { + /* Handle the reads less than 4 bytes... */ + uiData = 0; + memcpy(&uiData, ((PUCHAR)pBuffer) + (uiIndex * sizeof(unsigned int)), uiNumBytes); + BeceemEEPROMBulkRead(Adapter, &uiRdbk, uiOffset, 4); + + if (memcmp(&uiData, &uiRdbk, uiNumBytes)) + return -1; + + uiNumBytes = 0; + } + } + + return 0; +} + +static VOID BcmSwapWord(unsigned int *ptr1) +{ + unsigned int tempval = (unsigned int)*ptr1; + char *ptr2 = (char *)&tempval; + char *ptr = (char *)ptr1; + + ptr[0] = ptr2[3]; + ptr[1] = ptr2[2]; + ptr[2] = ptr2[1]; + ptr[3] = ptr2[0]; +} + +/* + * Procedure: BeceemEEPROMWritePage + * + * Description: Performs page write (16bytes) to the EEPROM + * + * Arguments: + * Adapter - ptr to Adapter object instance + * uiData - Data to be written. + * uiOffset - Offset of the EEPROM where data needs to be written to. + * Returns: + * OSAL_STATUS_CODE + * + */ + +static int BeceemEEPROMWritePage(struct bcm_mini_adapter *Adapter, unsigned int uiData[], unsigned int uiOffset) +{ + unsigned int uiRetries = MAX_EEPROM_RETRIES * RETRIES_PER_DELAY; + unsigned int uiStatus = 0; + UCHAR uiEpromStatus = 0; + unsigned int value = 0; + + /* Flush the Write/Read/Cmd queues. */ + value = (EEPROM_WRITE_QUEUE_FLUSH | EEPROM_CMD_QUEUE_FLUSH | EEPROM_READ_QUEUE_FLUSH); + wrmalt(Adapter, SPI_FLUSH_REG, &value, sizeof(value)); + value = 0; + wrmalt(Adapter, SPI_FLUSH_REG, &value, sizeof(value)); + + /* Clear the Empty/Avail/Full bits. After this it has been confirmed + * that the bit was cleared by reading back the register. See NOTE below. + * We also clear the Read queues as we do a EEPROM status register read + * later. + */ + value = (EEPROM_WRITE_QUEUE_EMPTY | EEPROM_WRITE_QUEUE_AVAIL | EEPROM_WRITE_QUEUE_FULL | EEPROM_READ_DATA_AVAIL | EEPROM_READ_DATA_FULL); + wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value)); + + /* Enable write */ + value = EEPROM_WRITE_ENABLE; + wrmalt(Adapter, EEPROM_CMDQ_SPI_REG, &value, sizeof(value)); + + /* We can write back to back 8bits * 16 into the queue and as we have + * checked for the queue to be empty we can write in a burst. + */ + + value = uiData[0]; + BcmSwapWord(&value); + wrm(Adapter, EEPROM_WRITE_DATAQ_REG, (PUCHAR)&value, 4); + + value = uiData[1]; + BcmSwapWord(&value); + wrm(Adapter, EEPROM_WRITE_DATAQ_REG, (PUCHAR)&value, 4); + + value = uiData[2]; + BcmSwapWord(&value); + wrm(Adapter, EEPROM_WRITE_DATAQ_REG, (PUCHAR)&value, 4); + + value = uiData[3]; + BcmSwapWord(&value); + wrm(Adapter, EEPROM_WRITE_DATAQ_REG, (PUCHAR)&value, 4); + + /* NOTE : After this write, on readback of EEPROM_SPI_Q_STATUS1_REG + * shows that we see 7 for the EEPROM data write. Which means that + * queue got full, also space is available as well as the queue is empty. + * This may happen in sequence. + */ + value = EEPROM_16_BYTE_PAGE_WRITE | uiOffset; + wrmalt(Adapter, EEPROM_CMDQ_SPI_REG, &value, sizeof(value)); + + /* Ideally we should loop here without tries and eventually succeed. + * What we are checking if the previous write has completed, and this + * may take time. We should wait till the Empty bit is set. + */ + uiStatus = 0; + rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &uiStatus, sizeof(uiStatus)); + while ((uiStatus & EEPROM_WRITE_QUEUE_EMPTY) == 0) { + uiRetries--; + if (uiRetries == 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "0x0f003004 = %x, %d retries failed.\n", uiStatus, MAX_EEPROM_RETRIES * RETRIES_PER_DELAY); + return STATUS_FAILURE; + } + + if (!(uiRetries%RETRIES_PER_DELAY)) + udelay(1000); + + uiStatus = 0; + rdmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &uiStatus, sizeof(uiStatus)); + if (Adapter->device_removed == TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Modem got removed hence exiting from loop...."); + return -ENODEV; + } + } + + if (uiRetries != 0) { + /* Clear the ones that are set - either, Empty/Full/Avail bits */ + value = (uiStatus & (EEPROM_WRITE_QUEUE_EMPTY | EEPROM_WRITE_QUEUE_AVAIL | EEPROM_WRITE_QUEUE_FULL)); + wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value)); + } + + /* Here we should check if the EEPROM status register is correct before + * proceeding. Bit 0 in the EEPROM Status register should be 0 before + * we proceed further. A 1 at Bit 0 indicates that the EEPROM is busy + * with the previous write. Note also that issuing this read finally + * means the previous write to the EEPROM has completed. + */ + uiRetries = MAX_EEPROM_RETRIES * RETRIES_PER_DELAY; + uiEpromStatus = 0; + while (uiRetries != 0) { + uiEpromStatus = ReadEEPROMStatusRegister(Adapter); + if (Adapter->device_removed == TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Modem has got removed hence exiting from loop..."); + return -ENODEV; + } + if ((EEPROM_STATUS_REG_WRITE_BUSY & uiEpromStatus) == 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "EEPROM status register = %x tries = %d\n", uiEpromStatus, (MAX_EEPROM_RETRIES * RETRIES_PER_DELAY - uiRetries)); + return STATUS_SUCCESS; + } + uiRetries--; + if (uiRetries == 0) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "0x0f003004 = %x, for EEPROM status read %d retries failed.\n", uiEpromStatus, MAX_EEPROM_RETRIES * RETRIES_PER_DELAY); + return STATUS_FAILURE; + } + uiEpromStatus = 0; + if (!(uiRetries%RETRIES_PER_DELAY)) + udelay(1000); + } + + return STATUS_SUCCESS; +} /* BeceemEEPROMWritePage */ + +/* + * Procedure: BeceemEEPROMBulkWrite + * + * Description: Performs write to the EEPROM + * + * Arguments: + * Adapter - ptr to Adapter object instance + * pBuffer - Data to be written. + * uiOffset - Offset of the EEPROM where data needs to be written to. + * uiNumBytes - Number of bytes to be written. + * bVerify - read verify flag. + * Returns: + * OSAL_STATUS_CODE + * + */ + +int BeceemEEPROMBulkWrite(struct bcm_mini_adapter *Adapter, + PUCHAR pBuffer, + unsigned int uiOffset, + unsigned int uiNumBytes, + bool bVerify) +{ + unsigned int uiBytesToCopy = uiNumBytes; + /* unsigned int uiRdbk = 0; */ + unsigned int uiData[4] = {0}; + unsigned int uiIndex = 0; + unsigned int uiTempOffset = 0; + unsigned int uiExtraBytes = 0; + /* PUINT puiBuffer = (PUINT)pBuffer; + * int value; + */ + + if (uiOffset % MAX_RW_SIZE && uiBytesToCopy) { + uiTempOffset = uiOffset - (uiOffset % MAX_RW_SIZE); + uiExtraBytes = uiOffset - uiTempOffset; + + BeceemEEPROMBulkRead(Adapter, &uiData[0], uiTempOffset, MAX_RW_SIZE); + + if (uiBytesToCopy >= (16 - uiExtraBytes)) { + memcpy((((PUCHAR)&uiData[0]) + uiExtraBytes), pBuffer, MAX_RW_SIZE - uiExtraBytes); + + if (STATUS_FAILURE == BeceemEEPROMWritePage(Adapter, uiData, uiTempOffset)) + return STATUS_FAILURE; + + uiBytesToCopy -= (MAX_RW_SIZE - uiExtraBytes); + uiIndex += (MAX_RW_SIZE - uiExtraBytes); + uiOffset += (MAX_RW_SIZE - uiExtraBytes); + } else { + memcpy((((PUCHAR)&uiData[0]) + uiExtraBytes), pBuffer, uiBytesToCopy); + + if (STATUS_FAILURE == BeceemEEPROMWritePage(Adapter, uiData, uiTempOffset)) + return STATUS_FAILURE; + + uiIndex += uiBytesToCopy; + uiOffset += uiBytesToCopy; + uiBytesToCopy = 0; + } + } + + while (uiBytesToCopy) { + if (Adapter->device_removed) + return -1; + + if (uiBytesToCopy >= MAX_RW_SIZE) { + if (STATUS_FAILURE == BeceemEEPROMWritePage(Adapter, (PUINT) &pBuffer[uiIndex], uiOffset)) + return STATUS_FAILURE; + + uiIndex += MAX_RW_SIZE; + uiOffset += MAX_RW_SIZE; + uiBytesToCopy -= MAX_RW_SIZE; + } else { + /* + * To program non 16byte aligned data, read 16byte and then update. + */ + BeceemEEPROMBulkRead(Adapter, &uiData[0], uiOffset, 16); + memcpy(&uiData[0], pBuffer + uiIndex, uiBytesToCopy); + + if (STATUS_FAILURE == BeceemEEPROMWritePage(Adapter, uiData, uiOffset)) + return STATUS_FAILURE; + + uiBytesToCopy = 0; + } + } + + return 0; +} + +/* + * Procedure: BeceemNVMRead + * + * Description: Reads n number of bytes from NVM. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * pBuffer - Buffer to store the data read from NVM + * uiOffset - Offset of NVM from where data should be read + * uiNumBytes - Number of bytes to be read from the NVM. + * + * Returns: + * OSAL_STATUS_SUCCESS - if NVM read is successful. + * <FAILURE> - if failed. + */ + +int BeceemNVMRead(struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + unsigned int uiOffset, + unsigned int uiNumBytes) +{ + int Status = 0; + + #if !defined(BCM_SHM_INTERFACE) || defined(FLASH_DIRECT_ACCESS) + unsigned int uiTemp = 0, value; + #endif + + if (Adapter->eNVMType == NVM_FLASH) { + if (Adapter->bFlashRawRead == false) { + if (IsSectionExistInVendorInfo(Adapter, Adapter->eActiveDSD)) + return vendorextnReadSection(Adapter, (PUCHAR)pBuffer, Adapter->eActiveDSD, uiOffset, uiNumBytes); + + uiOffset = uiOffset + Adapter->ulFlashCalStart; + } + + #if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS) + Status = bcmflash_raw_read((uiOffset / FLASH_PART_SIZE), (uiOffset % FLASH_PART_SIZE), (unsigned char *)pBuffer, uiNumBytes); + #else + rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp)); + value = 0; + wrmalt(Adapter, 0x0f000C80, &value, sizeof(value)); + Status = BeceemFlashBulkRead(Adapter, + pBuffer, + uiOffset, + uiNumBytes); + wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp)); + #endif + } else if (Adapter->eNVMType == NVM_EEPROM) { + Status = BeceemEEPROMBulkRead(Adapter, + pBuffer, + uiOffset, + uiNumBytes); + } else { + Status = -1; + } + + return Status; +} + +/* + * Procedure: BeceemNVMWrite + * + * Description: Writes n number of bytes to NVM. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * pBuffer - Buffer contains the data to be written. + * uiOffset - Offset of NVM where data to be written to. + * uiNumBytes - Number of bytes to be written.. + * + * Returns: + * OSAL_STATUS_SUCCESS - if NVM write is successful. + * <FAILURE> - if failed. + */ + +int BeceemNVMWrite(struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + unsigned int uiOffset, + unsigned int uiNumBytes, + bool bVerify) +{ + int Status = 0; + unsigned int uiTemp = 0; + unsigned int uiMemoryLoc = EEPROM_CAL_DATA_INTERNAL_LOC; + unsigned int uiIndex = 0; + + #if !defined(BCM_SHM_INTERFACE) || defined(FLASH_DIRECT_ACCESS) + unsigned int value; + #endif + + unsigned int uiFlashOffset = 0; + + if (Adapter->eNVMType == NVM_FLASH) { + if (IsSectionExistInVendorInfo(Adapter, Adapter->eActiveDSD)) + Status = vendorextnWriteSection(Adapter, (PUCHAR)pBuffer, Adapter->eActiveDSD, uiOffset, uiNumBytes, bVerify); + else { + uiFlashOffset = uiOffset + Adapter->ulFlashCalStart; + + #if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS) + Status = bcmflash_raw_write((uiFlashOffset / FLASH_PART_SIZE), (uiFlashOffset % FLASH_PART_SIZE), (unsigned char *)pBuffer, uiNumBytes); + #else + rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp)); + value = 0; + wrmalt(Adapter, 0x0f000C80, &value, sizeof(value)); + + if (Adapter->bStatusWrite == TRUE) + Status = BeceemFlashBulkWriteStatus(Adapter, + pBuffer, + uiFlashOffset, + uiNumBytes , + bVerify); + else + + Status = BeceemFlashBulkWrite(Adapter, + pBuffer, + uiFlashOffset, + uiNumBytes, + bVerify); + #endif + } + + if (uiOffset >= EEPROM_CALPARAM_START) { + uiMemoryLoc += (uiOffset - EEPROM_CALPARAM_START); + while (uiNumBytes) { + if (uiNumBytes > BUFFER_4K) { + wrm(Adapter, (uiMemoryLoc+uiIndex), (PCHAR)(pBuffer + (uiIndex / 4)), BUFFER_4K); + uiNumBytes -= BUFFER_4K; + uiIndex += BUFFER_4K; + } else { + wrm(Adapter, uiMemoryLoc+uiIndex, (PCHAR)(pBuffer + (uiIndex / 4)), uiNumBytes); + uiNumBytes = 0; + break; + } + } + } else { + if ((uiOffset + uiNumBytes) > EEPROM_CALPARAM_START) { + ULONG ulBytesTobeSkipped = 0; + PUCHAR pcBuffer = (PUCHAR)pBuffer; /* char pointer to take care of odd byte cases. */ + uiNumBytes -= (EEPROM_CALPARAM_START - uiOffset); + ulBytesTobeSkipped += (EEPROM_CALPARAM_START - uiOffset); + uiOffset += (EEPROM_CALPARAM_START - uiOffset); + while (uiNumBytes) { + if (uiNumBytes > BUFFER_4K) { + wrm(Adapter, uiMemoryLoc + uiIndex, (PCHAR)&pcBuffer[ulBytesTobeSkipped + uiIndex], BUFFER_4K); + uiNumBytes -= BUFFER_4K; + uiIndex += BUFFER_4K; + } else { + wrm(Adapter, uiMemoryLoc + uiIndex, (PCHAR)&pcBuffer[ulBytesTobeSkipped + uiIndex], uiNumBytes); + uiNumBytes = 0; + break; + } + } + } + } + /* restore the values. */ + wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp)); + } else if (Adapter->eNVMType == NVM_EEPROM) { + Status = BeceemEEPROMBulkWrite(Adapter, + (PUCHAR)pBuffer, + uiOffset, + uiNumBytes, + bVerify); + if (bVerify) + Status = BeceemEEPROMReadBackandVerify(Adapter, (PUINT)pBuffer, uiOffset, uiNumBytes); + } else { + Status = -1; + } + return Status; +} + +/* + * Procedure: BcmUpdateSectorSize + * + * Description: Updates the sector size to FLASH. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * uiSectorSize - sector size + * + * Returns: + * OSAL_STATUS_SUCCESS - if NVM write is successful. + * <FAILURE> - if failed. + */ + +int BcmUpdateSectorSize(struct bcm_mini_adapter *Adapter, unsigned int uiSectorSize) +{ + int Status = -1; + struct bcm_flash_cs_info sFlashCsInfo = {0}; + unsigned int uiTemp = 0; + unsigned int uiSectorSig = 0; + unsigned int uiCurrentSectorSize = 0; + unsigned int value; + + rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp)); + value = 0; + wrmalt(Adapter, 0x0f000C80, &value, sizeof(value)); + + /* + * Before updating the sector size in the reserved area, check if already present. + */ + BeceemFlashBulkRead(Adapter, (PUINT)&sFlashCsInfo, Adapter->ulFlashControlSectionStart, sizeof(sFlashCsInfo)); + uiSectorSig = ntohl(sFlashCsInfo.FlashSectorSizeSig); + uiCurrentSectorSize = ntohl(sFlashCsInfo.FlashSectorSize); + + if (uiSectorSig == FLASH_SECTOR_SIZE_SIG) { + if ((uiCurrentSectorSize <= MAX_SECTOR_SIZE) && (uiCurrentSectorSize >= MIN_SECTOR_SIZE)) { + if (uiSectorSize == uiCurrentSectorSize) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Provided sector size is same as programmed in Flash"); + Status = STATUS_SUCCESS; + goto Restore; + } + } + } + + if ((uiSectorSize <= MAX_SECTOR_SIZE) && (uiSectorSize >= MIN_SECTOR_SIZE)) { + sFlashCsInfo.FlashSectorSize = htonl(uiSectorSize); + sFlashCsInfo.FlashSectorSizeSig = htonl(FLASH_SECTOR_SIZE_SIG); + + Status = BeceemFlashBulkWrite(Adapter, + (PUINT)&sFlashCsInfo, + Adapter->ulFlashControlSectionStart, + sizeof(sFlashCsInfo), + TRUE); + } + +Restore: + /* restore the values. */ + wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp)); + + return Status; +} + +/* + * Procedure: BcmGetFlashSectorSize + * + * Description: Finds the sector size of the FLASH. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * + * Returns: + * unsigned int - sector size. + * + */ + +static unsigned int BcmGetFlashSectorSize(struct bcm_mini_adapter *Adapter, unsigned int FlashSectorSizeSig, unsigned int FlashSectorSize) +{ + unsigned int uiSectorSize = 0; + unsigned int uiSectorSig = 0; + + if (Adapter->bSectorSizeOverride && + (Adapter->uiSectorSizeInCFG <= MAX_SECTOR_SIZE && + Adapter->uiSectorSizeInCFG >= MIN_SECTOR_SIZE)) { + Adapter->uiSectorSize = Adapter->uiSectorSizeInCFG; + } else { + uiSectorSig = FlashSectorSizeSig; + + if (uiSectorSig == FLASH_SECTOR_SIZE_SIG) { + uiSectorSize = FlashSectorSize; + /* + * If the sector size stored in the FLASH makes sense then use it. + */ + if (uiSectorSize <= MAX_SECTOR_SIZE && uiSectorSize >= MIN_SECTOR_SIZE) { + Adapter->uiSectorSize = uiSectorSize; + } else if (Adapter->uiSectorSizeInCFG <= MAX_SECTOR_SIZE && + Adapter->uiSectorSizeInCFG >= MIN_SECTOR_SIZE) { + /* No valid size in FLASH, check if Config file has it. */ + Adapter->uiSectorSize = Adapter->uiSectorSizeInCFG; + } else { + /* Init to Default, if none of the above works. */ + Adapter->uiSectorSize = DEFAULT_SECTOR_SIZE; + } + } else { + if (Adapter->uiSectorSizeInCFG <= MAX_SECTOR_SIZE && + Adapter->uiSectorSizeInCFG >= MIN_SECTOR_SIZE) + Adapter->uiSectorSize = Adapter->uiSectorSizeInCFG; + else + Adapter->uiSectorSize = DEFAULT_SECTOR_SIZE; + } + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Sector size :%x\n", Adapter->uiSectorSize); + + return Adapter->uiSectorSize; +} + +/* + * Procedure: BcmInitEEPROMQueues + * + * Description: Initialization of EEPROM queues. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * + * Returns: + * <OSAL_STATUS_CODE> + */ + +static int BcmInitEEPROMQueues(struct bcm_mini_adapter *Adapter) +{ + unsigned int value = 0; + /* CHIP Bug : Clear the Avail bits on the Read queue. The default + * value on this register is supposed to be 0x00001102. + * But we get 0x00001122. + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Fixing reset value on 0x0f003004 register\n"); + value = EEPROM_READ_DATA_AVAIL; + wrmalt(Adapter, EEPROM_SPI_Q_STATUS1_REG, &value, sizeof(value)); + + /* Flush the all the EEPROM queues. */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, " Flushing the queues\n"); + value = EEPROM_ALL_QUEUE_FLUSH; + wrmalt(Adapter, SPI_FLUSH_REG, &value, sizeof(value)); + + value = 0; + wrmalt(Adapter, SPI_FLUSH_REG, &value, sizeof(value)); + + /* Read the EEPROM Status Register. Just to see, no real purpose. */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "EEPROM Status register value = %x\n", ReadEEPROMStatusRegister(Adapter)); + + return STATUS_SUCCESS; +} /* BcmInitEEPROMQueues() */ + +/* + * Procedure: BcmInitNVM + * + * Description: Initialization of NVM, EEPROM size,FLASH size, sector size etc. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * + * Returns: + * <OSAL_STATUS_CODE> + */ + +int BcmInitNVM(struct bcm_mini_adapter *ps_adapter) +{ + BcmValidateNvmType(ps_adapter); + BcmInitEEPROMQueues(ps_adapter); + + if (ps_adapter->eNVMType == NVM_AUTODETECT) { + ps_adapter->eNVMType = BcmGetNvmType(ps_adapter); + if (ps_adapter->eNVMType == NVM_UNKNOWN) + BCM_DEBUG_PRINT(ps_adapter, DBG_TYPE_PRINTK, 0, 0, "NVM Type is unknown!!\n"); + } else if (ps_adapter->eNVMType == NVM_FLASH) { + BcmGetFlashCSInfo(ps_adapter); + } + + BcmGetNvmSize(ps_adapter); + + return STATUS_SUCCESS; +} + +/* BcmGetNvmSize : set the EEPROM or flash size in Adapter. + * + * Input Parameter: + * Adapter data structure + * Return Value : + * 0. means success; + */ + +static int BcmGetNvmSize(struct bcm_mini_adapter *Adapter) +{ + if (Adapter->eNVMType == NVM_EEPROM) + Adapter->uiNVMDSDSize = BcmGetEEPROMSize(Adapter); + else if (Adapter->eNVMType == NVM_FLASH) + Adapter->uiNVMDSDSize = BcmGetFlashSize(Adapter); + + return 0; +} + +/* + * Procedure: BcmValidateNvm + * + * Description: Validates the NVM Type option selected against the device + * + * Arguments: + * Adapter - ptr to Adapter object instance + * + * Returns: + * <VOID> + */ + +static VOID BcmValidateNvmType(struct bcm_mini_adapter *Adapter) +{ + /* + * if forcing the FLASH through CFG file, we should ensure device really has a FLASH. + * Accessing the FLASH address without the FLASH being present can cause hang/freeze etc. + * So if NVM_FLASH is selected for older chipsets, change it to AUTODETECT where EEPROM is 1st choice. + */ + + if (Adapter->eNVMType == NVM_FLASH && + Adapter->chip_id < 0xBECE3300) + Adapter->eNVMType = NVM_AUTODETECT; +} + +/* + * Procedure: BcmReadFlashRDID + * + * Description: Reads ID from Serial Flash + * + * Arguments: + * Adapter - ptr to Adapter object instance + * + * Returns: + * Flash ID + */ + +static ULONG BcmReadFlashRDID(struct bcm_mini_adapter *Adapter) +{ + ULONG ulRDID = 0; + unsigned int value; + + /* + * Read ID Instruction. + */ + value = (FLASH_CMD_READ_ID << 24); + wrmalt(Adapter, FLASH_SPI_CMDQ_REG, &value, sizeof(value)); + + /* Delay */ + udelay(10); + + /* + * Read SPI READQ REG. The output will be WWXXYYZZ. + * The ID is 3Bytes long and is WWXXYY. ZZ needs to be Ignored. + */ + rdmalt(Adapter, FLASH_SPI_READQ_REG, (PUINT)&ulRDID, sizeof(ulRDID)); + + return ulRDID >> 8; +} + +int BcmAllocFlashCSStructure(struct bcm_mini_adapter *psAdapter) +{ + if (!psAdapter) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Adapter structure point is NULL"); + return -EINVAL; + } + psAdapter->psFlashCSInfo = kzalloc(sizeof(struct bcm_flash_cs_info), GFP_KERNEL); + if (psAdapter->psFlashCSInfo == NULL) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate memory for Flash 1.x"); + return -ENOMEM; + } + + psAdapter->psFlash2xCSInfo = kzalloc(sizeof(struct bcm_flash2x_cs_info), GFP_KERNEL); + if (!psAdapter->psFlash2xCSInfo) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate memory for Flash 2.x"); + kfree(psAdapter->psFlashCSInfo); + return -ENOMEM; + } + + psAdapter->psFlash2xVendorInfo = kzalloc(sizeof(struct bcm_flash2x_vendor_info), GFP_KERNEL); + if (!psAdapter->psFlash2xVendorInfo) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Can't Allocate Vendor Info Memory for Flash 2.x"); + kfree(psAdapter->psFlashCSInfo); + kfree(psAdapter->psFlash2xCSInfo); + return -ENOMEM; + } + + return STATUS_SUCCESS; +} + +int BcmDeAllocFlashCSStructure(struct bcm_mini_adapter *psAdapter) +{ + if (!psAdapter) { + BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_PRINTK, 0, 0, "Adapter structure point is NULL"); + return -EINVAL; + } + kfree(psAdapter->psFlashCSInfo); + kfree(psAdapter->psFlash2xCSInfo); + kfree(psAdapter->psFlash2xVendorInfo); + return STATUS_SUCCESS; +} + +static int BcmDumpFlash2XCSStructure(struct bcm_flash2x_cs_info *psFlash2xCSInfo, struct bcm_mini_adapter *Adapter) +{ + unsigned int Index = 0; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "**********************FLASH2X CS Structure *******************"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Signature is :%x", (psFlash2xCSInfo->MagicNumber)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Flash Major Version :%d", MAJOR_VERSION(psFlash2xCSInfo->FlashLayoutVersion)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Flash Minor Version :%d", MINOR_VERSION(psFlash2xCSInfo->FlashLayoutVersion)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, " ISOImageMajorVersion:0x%x", (psFlash2xCSInfo->ISOImageVersion)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SCSIFirmwareMajorVersion :0x%x", (psFlash2xCSInfo->SCSIFirmwareVersion)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForPart1ISOImage :0x%x", (psFlash2xCSInfo->OffsetFromZeroForPart1ISOImage)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForScsiFirmware :0x%x", (psFlash2xCSInfo->OffsetFromZeroForScsiFirmware)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SizeOfScsiFirmware :0x%x", (psFlash2xCSInfo->SizeOfScsiFirmware)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForPart2ISOImage :0x%x", (psFlash2xCSInfo->OffsetFromZeroForPart2ISOImage)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSDStart :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSDStart)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSDEnd :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSDEnd)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSAStart :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSAStart)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSAEnd :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSAEnd)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForControlSectionStart :0x%x", (psFlash2xCSInfo->OffsetFromZeroForControlSectionStart)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForControlSectionData :0x%x", (psFlash2xCSInfo->OffsetFromZeroForControlSectionData)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "CDLessInactivityTimeout :0x%x", (psFlash2xCSInfo->CDLessInactivityTimeout)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "NewImageSignature :0x%x", (psFlash2xCSInfo->NewImageSignature)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashSectorSizeSig :0x%x", (psFlash2xCSInfo->FlashSectorSizeSig)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashSectorSize :0x%x", (psFlash2xCSInfo->FlashSectorSize)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashWriteSupportSize :0x%x", (psFlash2xCSInfo->FlashWriteSupportSize)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "TotalFlashSize :0x%X", (psFlash2xCSInfo->TotalFlashSize)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashBaseAddr :0x%x", (psFlash2xCSInfo->FlashBaseAddr)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FlashPartMaxSize :0x%x", (psFlash2xCSInfo->FlashPartMaxSize)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "IsCDLessDeviceBootSig :0x%x", (psFlash2xCSInfo->IsCDLessDeviceBootSig)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "MassStorageTimeout :0x%x", (psFlash2xCSInfo->MassStorageTimeout)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part1Start :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part1Start)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part1End :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part1End)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part2Start :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part2Start)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part2End :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part2End)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part3Start :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part3Start)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage1Part3End :0x%x", (psFlash2xCSInfo->OffsetISOImage1Part3End)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part1Start :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part1Start)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part1End :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part1End)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part2Start :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part2Start)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part2End :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part2End)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part3Start :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part3Start)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetISOImage2Part3End :0x%x", (psFlash2xCSInfo->OffsetISOImage2Part3End)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromDSDStartForDSDHeader :0x%x", (psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSD1Start :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSD1Start)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSD1End :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSD1End)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSD2Start :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSD2Start)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForDSD2End :0x%x", (psFlash2xCSInfo->OffsetFromZeroForDSD2End)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSA1Start :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSA1Start)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSA1End :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSA1End)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSA2Start :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSA2Start)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "OffsetFromZeroForVSA2End :0x%x", (psFlash2xCSInfo->OffsetFromZeroForVSA2End)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Sector Access Bit Map is Defined as :"); + + for (Index = 0; Index < (FLASH2X_TOTAL_SIZE / (DEFAULT_SECTOR_SIZE * 16)); Index++) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SectorAccessBitMap[%d] :0x%x", Index, + (psFlash2xCSInfo->SectorAccessBitMap[Index])); + + return STATUS_SUCCESS; +} + +static int ConvertEndianOf2XCSStructure(struct bcm_flash2x_cs_info *psFlash2xCSInfo) +{ + unsigned int Index = 0; + + psFlash2xCSInfo->MagicNumber = ntohl(psFlash2xCSInfo->MagicNumber); + psFlash2xCSInfo->FlashLayoutVersion = ntohl(psFlash2xCSInfo->FlashLayoutVersion); + /* psFlash2xCSInfo->FlashLayoutMinorVersion = ntohs(psFlash2xCSInfo->FlashLayoutMinorVersion); */ + psFlash2xCSInfo->ISOImageVersion = ntohl(psFlash2xCSInfo->ISOImageVersion); + psFlash2xCSInfo->SCSIFirmwareVersion = ntohl(psFlash2xCSInfo->SCSIFirmwareVersion); + psFlash2xCSInfo->OffsetFromZeroForPart1ISOImage = ntohl(psFlash2xCSInfo->OffsetFromZeroForPart1ISOImage); + psFlash2xCSInfo->OffsetFromZeroForScsiFirmware = ntohl(psFlash2xCSInfo->OffsetFromZeroForScsiFirmware); + psFlash2xCSInfo->SizeOfScsiFirmware = ntohl(psFlash2xCSInfo->SizeOfScsiFirmware); + psFlash2xCSInfo->OffsetFromZeroForPart2ISOImage = ntohl(psFlash2xCSInfo->OffsetFromZeroForPart2ISOImage); + psFlash2xCSInfo->OffsetFromZeroForDSDStart = ntohl(psFlash2xCSInfo->OffsetFromZeroForDSDStart); + psFlash2xCSInfo->OffsetFromZeroForDSDEnd = ntohl(psFlash2xCSInfo->OffsetFromZeroForDSDEnd); + psFlash2xCSInfo->OffsetFromZeroForVSAStart = ntohl(psFlash2xCSInfo->OffsetFromZeroForVSAStart); + psFlash2xCSInfo->OffsetFromZeroForVSAEnd = ntohl(psFlash2xCSInfo->OffsetFromZeroForVSAEnd); + psFlash2xCSInfo->OffsetFromZeroForControlSectionStart = ntohl(psFlash2xCSInfo->OffsetFromZeroForControlSectionStart); + psFlash2xCSInfo->OffsetFromZeroForControlSectionData = ntohl(psFlash2xCSInfo->OffsetFromZeroForControlSectionData); + psFlash2xCSInfo->CDLessInactivityTimeout = ntohl(psFlash2xCSInfo->CDLessInactivityTimeout); + psFlash2xCSInfo->NewImageSignature = ntohl(psFlash2xCSInfo->NewImageSignature); + psFlash2xCSInfo->FlashSectorSizeSig = ntohl(psFlash2xCSInfo->FlashSectorSizeSig); + psFlash2xCSInfo->FlashSectorSize = ntohl(psFlash2xCSInfo->FlashSectorSize); + psFlash2xCSInfo->FlashWriteSupportSize = ntohl(psFlash2xCSInfo->FlashWriteSupportSize); + psFlash2xCSInfo->TotalFlashSize = ntohl(psFlash2xCSInfo->TotalFlashSize); + psFlash2xCSInfo->FlashBaseAddr = ntohl(psFlash2xCSInfo->FlashBaseAddr); + psFlash2xCSInfo->FlashPartMaxSize = ntohl(psFlash2xCSInfo->FlashPartMaxSize); + psFlash2xCSInfo->IsCDLessDeviceBootSig = ntohl(psFlash2xCSInfo->IsCDLessDeviceBootSig); + psFlash2xCSInfo->MassStorageTimeout = ntohl(psFlash2xCSInfo->MassStorageTimeout); + psFlash2xCSInfo->OffsetISOImage1Part1Start = ntohl(psFlash2xCSInfo->OffsetISOImage1Part1Start); + psFlash2xCSInfo->OffsetISOImage1Part1End = ntohl(psFlash2xCSInfo->OffsetISOImage1Part1End); + psFlash2xCSInfo->OffsetISOImage1Part2Start = ntohl(psFlash2xCSInfo->OffsetISOImage1Part2Start); + psFlash2xCSInfo->OffsetISOImage1Part2End = ntohl(psFlash2xCSInfo->OffsetISOImage1Part2End); + psFlash2xCSInfo->OffsetISOImage1Part3Start = ntohl(psFlash2xCSInfo->OffsetISOImage1Part3Start); + psFlash2xCSInfo->OffsetISOImage1Part3End = ntohl(psFlash2xCSInfo->OffsetISOImage1Part3End); + psFlash2xCSInfo->OffsetISOImage2Part1Start = ntohl(psFlash2xCSInfo->OffsetISOImage2Part1Start); + psFlash2xCSInfo->OffsetISOImage2Part1End = ntohl(psFlash2xCSInfo->OffsetISOImage2Part1End); + psFlash2xCSInfo->OffsetISOImage2Part2Start = ntohl(psFlash2xCSInfo->OffsetISOImage2Part2Start); + psFlash2xCSInfo->OffsetISOImage2Part2End = ntohl(psFlash2xCSInfo->OffsetISOImage2Part2End); + psFlash2xCSInfo->OffsetISOImage2Part3Start = ntohl(psFlash2xCSInfo->OffsetISOImage2Part3Start); + psFlash2xCSInfo->OffsetISOImage2Part3End = ntohl(psFlash2xCSInfo->OffsetISOImage2Part3End); + psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader = ntohl(psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader); + psFlash2xCSInfo->OffsetFromZeroForDSD1Start = ntohl(psFlash2xCSInfo->OffsetFromZeroForDSD1Start); + psFlash2xCSInfo->OffsetFromZeroForDSD1End = ntohl(psFlash2xCSInfo->OffsetFromZeroForDSD1End); + psFlash2xCSInfo->OffsetFromZeroForDSD2Start = ntohl(psFlash2xCSInfo->OffsetFromZeroForDSD2Start); + psFlash2xCSInfo->OffsetFromZeroForDSD2End = ntohl(psFlash2xCSInfo->OffsetFromZeroForDSD2End); + psFlash2xCSInfo->OffsetFromZeroForVSA1Start = ntohl(psFlash2xCSInfo->OffsetFromZeroForVSA1Start); + psFlash2xCSInfo->OffsetFromZeroForVSA1End = ntohl(psFlash2xCSInfo->OffsetFromZeroForVSA1End); + psFlash2xCSInfo->OffsetFromZeroForVSA2Start = ntohl(psFlash2xCSInfo->OffsetFromZeroForVSA2Start); + psFlash2xCSInfo->OffsetFromZeroForVSA2End = ntohl(psFlash2xCSInfo->OffsetFromZeroForVSA2End); + + for (Index = 0; Index < (FLASH2X_TOTAL_SIZE / (DEFAULT_SECTOR_SIZE * 16)); Index++) + psFlash2xCSInfo->SectorAccessBitMap[Index] = ntohl(psFlash2xCSInfo->SectorAccessBitMap[Index]); + + return STATUS_SUCCESS; +} + +static int ConvertEndianOfCSStructure(struct bcm_flash_cs_info *psFlashCSInfo) +{ + /* unsigned int Index = 0; */ + psFlashCSInfo->MagicNumber = ntohl(psFlashCSInfo->MagicNumber); + psFlashCSInfo->FlashLayoutVersion = ntohl(psFlashCSInfo->FlashLayoutVersion); + psFlashCSInfo->ISOImageVersion = ntohl(psFlashCSInfo->ISOImageVersion); + /* won't convert according to old assumption */ + psFlashCSInfo->SCSIFirmwareVersion = (psFlashCSInfo->SCSIFirmwareVersion); + psFlashCSInfo->OffsetFromZeroForPart1ISOImage = ntohl(psFlashCSInfo->OffsetFromZeroForPart1ISOImage); + psFlashCSInfo->OffsetFromZeroForScsiFirmware = ntohl(psFlashCSInfo->OffsetFromZeroForScsiFirmware); + psFlashCSInfo->SizeOfScsiFirmware = ntohl(psFlashCSInfo->SizeOfScsiFirmware); + psFlashCSInfo->OffsetFromZeroForPart2ISOImage = ntohl(psFlashCSInfo->OffsetFromZeroForPart2ISOImage); + psFlashCSInfo->OffsetFromZeroForCalibrationStart = ntohl(psFlashCSInfo->OffsetFromZeroForCalibrationStart); + psFlashCSInfo->OffsetFromZeroForCalibrationEnd = ntohl(psFlashCSInfo->OffsetFromZeroForCalibrationEnd); + psFlashCSInfo->OffsetFromZeroForVSAStart = ntohl(psFlashCSInfo->OffsetFromZeroForVSAStart); + psFlashCSInfo->OffsetFromZeroForVSAEnd = ntohl(psFlashCSInfo->OffsetFromZeroForVSAEnd); + psFlashCSInfo->OffsetFromZeroForControlSectionStart = ntohl(psFlashCSInfo->OffsetFromZeroForControlSectionStart); + psFlashCSInfo->OffsetFromZeroForControlSectionData = ntohl(psFlashCSInfo->OffsetFromZeroForControlSectionData); + psFlashCSInfo->CDLessInactivityTimeout = ntohl(psFlashCSInfo->CDLessInactivityTimeout); + psFlashCSInfo->NewImageSignature = ntohl(psFlashCSInfo->NewImageSignature); + psFlashCSInfo->FlashSectorSizeSig = ntohl(psFlashCSInfo->FlashSectorSizeSig); + psFlashCSInfo->FlashSectorSize = ntohl(psFlashCSInfo->FlashSectorSize); + psFlashCSInfo->FlashWriteSupportSize = ntohl(psFlashCSInfo->FlashWriteSupportSize); + psFlashCSInfo->TotalFlashSize = ntohl(psFlashCSInfo->TotalFlashSize); + psFlashCSInfo->FlashBaseAddr = ntohl(psFlashCSInfo->FlashBaseAddr); + psFlashCSInfo->FlashPartMaxSize = ntohl(psFlashCSInfo->FlashPartMaxSize); + psFlashCSInfo->IsCDLessDeviceBootSig = ntohl(psFlashCSInfo->IsCDLessDeviceBootSig); + psFlashCSInfo->MassStorageTimeout = ntohl(psFlashCSInfo->MassStorageTimeout); + + return STATUS_SUCCESS; +} + +static int IsSectionExistInVendorInfo(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val section) +{ + return (Adapter->uiVendorExtnFlag && + (Adapter->psFlash2xVendorInfo->VendorSection[section].AccessFlags & FLASH2X_SECTION_PRESENT) && + (Adapter->psFlash2xVendorInfo->VendorSection[section].OffsetFromZeroForSectionStart != UNINIT_PTR_IN_CS)); +} + +static VOID UpdateVendorInfo(struct bcm_mini_adapter *Adapter) +{ + B_UINT32 i = 0; + unsigned int uiSizeSection = 0; + + Adapter->uiVendorExtnFlag = false; + + for (i = 0; i < TOTAL_SECTIONS; i++) + Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart = UNINIT_PTR_IN_CS; + + if (STATUS_SUCCESS != vendorextnGetSectionInfo(Adapter, Adapter->psFlash2xVendorInfo)) + return; + + i = 0; + while (i < TOTAL_SECTIONS) { + if (!(Adapter->psFlash2xVendorInfo->VendorSection[i].AccessFlags & FLASH2X_SECTION_PRESENT)) { + i++; + continue; + } + + Adapter->uiVendorExtnFlag = TRUE; + uiSizeSection = (Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionEnd - + Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart); + + switch (i) { + case DSD0: + if ((uiSizeSection >= (Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(struct bcm_dsd_header))) && + (UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart)) + Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDEnd = VENDOR_PTR_IN_CS; + else + Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDEnd = UNINIT_PTR_IN_CS; + break; + + case DSD1: + if ((uiSizeSection >= (Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(struct bcm_dsd_header))) && + (UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart)) + Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1End = VENDOR_PTR_IN_CS; + else + Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1End = UNINIT_PTR_IN_CS; + break; + + case DSD2: + if ((uiSizeSection >= (Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(struct bcm_dsd_header))) && + (UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart)) + Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2End = VENDOR_PTR_IN_CS; + else + Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2End = UNINIT_PTR_IN_CS; + break; + case VSA0: + if (UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart) + Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAEnd = VENDOR_PTR_IN_CS; + else + Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAEnd = UNINIT_PTR_IN_CS; + break; + + case VSA1: + if (UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart) + Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1End = VENDOR_PTR_IN_CS; + else + Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1End = UNINIT_PTR_IN_CS; + break; + case VSA2: + if (UNINIT_PTR_IN_CS != Adapter->psFlash2xVendorInfo->VendorSection[i].OffsetFromZeroForSectionStart) + Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2End = VENDOR_PTR_IN_CS; + else + Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2Start = Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2End = UNINIT_PTR_IN_CS; + break; + + default: + break; + } + i++; + } +} + +/* + * Procedure: BcmGetFlashCSInfo + * + * Description: Reads control structure and gets Cal section addresses. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * + * Returns: + * <VOID> + */ + +static int BcmGetFlashCSInfo(struct bcm_mini_adapter *Adapter) +{ + /* struct bcm_flash_cs_info sFlashCsInfo = {0}; */ + + #if !defined(BCM_SHM_INTERFACE) || defined(FLASH_DIRECT_ACCESS) + unsigned int value; + #endif + + unsigned int uiFlashLayoutMajorVersion; + Adapter->uiFlashLayoutMinorVersion = 0; + Adapter->uiFlashLayoutMajorVersion = 0; + Adapter->ulFlashControlSectionStart = FLASH_CS_INFO_START_ADDR; + + Adapter->uiFlashBaseAdd = 0; + Adapter->ulFlashCalStart = 0; + memset(Adapter->psFlashCSInfo, 0 , sizeof(struct bcm_flash_cs_info)); + memset(Adapter->psFlash2xCSInfo, 0 , sizeof(struct bcm_flash2x_cs_info)); + + if (!Adapter->bDDRInitDone) { + value = FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT; + wrmalt(Adapter, 0xAF00A080, &value, sizeof(value)); + } + + /* Reading first 8 Bytes to get the Flash Layout + * MagicNumber(4 bytes) +FlashLayoutMinorVersion(2 Bytes) +FlashLayoutMajorVersion(2 Bytes) + */ + BeceemFlashBulkRead(Adapter, (PUINT)Adapter->psFlashCSInfo, Adapter->ulFlashControlSectionStart, 8); + + Adapter->psFlashCSInfo->FlashLayoutVersion = ntohl(Adapter->psFlashCSInfo->FlashLayoutVersion); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Flash Layout Version :%X", (Adapter->psFlashCSInfo->FlashLayoutVersion)); + /* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Flash Layout Minor Version :%d\n", ntohs(sFlashCsInfo.FlashLayoutMinorVersion)); */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Signature is :%x\n", ntohl(Adapter->psFlashCSInfo->MagicNumber)); + + if (FLASH_CONTROL_STRUCT_SIGNATURE == ntohl(Adapter->psFlashCSInfo->MagicNumber)) { + uiFlashLayoutMajorVersion = MAJOR_VERSION((Adapter->psFlashCSInfo->FlashLayoutVersion)); + Adapter->uiFlashLayoutMinorVersion = MINOR_VERSION((Adapter->psFlashCSInfo->FlashLayoutVersion)); + } else { + Adapter->uiFlashLayoutMinorVersion = 0; + uiFlashLayoutMajorVersion = 0; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "FLASH LAYOUT MAJOR VERSION :%X", uiFlashLayoutMajorVersion); + + if (uiFlashLayoutMajorVersion < FLASH_2X_MAJOR_NUMBER) { + BeceemFlashBulkRead(Adapter, (PUINT)Adapter->psFlashCSInfo, Adapter->ulFlashControlSectionStart, sizeof(struct bcm_flash_cs_info)); + ConvertEndianOfCSStructure(Adapter->psFlashCSInfo); + Adapter->ulFlashCalStart = (Adapter->psFlashCSInfo->OffsetFromZeroForCalibrationStart); + + if (!((Adapter->uiFlashLayoutMajorVersion == 1) && (Adapter->uiFlashLayoutMinorVersion == 1))) + Adapter->ulFlashControlSectionStart = Adapter->psFlashCSInfo->OffsetFromZeroForControlSectionStart; + + if ((FLASH_CONTROL_STRUCT_SIGNATURE == (Adapter->psFlashCSInfo->MagicNumber)) && + (SCSI_FIRMWARE_MINOR_VERSION <= MINOR_VERSION(Adapter->psFlashCSInfo->SCSIFirmwareVersion)) && + (FLASH_SECTOR_SIZE_SIG == (Adapter->psFlashCSInfo->FlashSectorSizeSig)) && + (BYTE_WRITE_SUPPORT == (Adapter->psFlashCSInfo->FlashWriteSupportSize))) { + Adapter->ulFlashWriteSize = (Adapter->psFlashCSInfo->FlashWriteSupportSize); + Adapter->fpFlashWrite = flashByteWrite; + Adapter->fpFlashWriteWithStatusCheck = flashByteWriteStatus; + } else { + Adapter->ulFlashWriteSize = MAX_RW_SIZE; + Adapter->fpFlashWrite = flashWrite; + Adapter->fpFlashWriteWithStatusCheck = flashWriteStatus; + } + + BcmGetFlashSectorSize(Adapter, (Adapter->psFlashCSInfo->FlashSectorSizeSig), + (Adapter->psFlashCSInfo->FlashSectorSize)); + Adapter->uiFlashBaseAdd = Adapter->psFlashCSInfo->FlashBaseAddr & 0xFCFFFFFF; + } else { + if (BcmFlash2xBulkRead(Adapter, (PUINT)Adapter->psFlash2xCSInfo, NO_SECTION_VAL, + Adapter->ulFlashControlSectionStart, sizeof(struct bcm_flash2x_cs_info))) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Unable to read CS structure\n"); + return STATUS_FAILURE; + } + + ConvertEndianOf2XCSStructure(Adapter->psFlash2xCSInfo); + BcmDumpFlash2XCSStructure(Adapter->psFlash2xCSInfo, Adapter); + if ((FLASH_CONTROL_STRUCT_SIGNATURE == Adapter->psFlash2xCSInfo->MagicNumber) && + (SCSI_FIRMWARE_MINOR_VERSION <= MINOR_VERSION(Adapter->psFlash2xCSInfo->SCSIFirmwareVersion)) && + (FLASH_SECTOR_SIZE_SIG == Adapter->psFlash2xCSInfo->FlashSectorSizeSig) && + (BYTE_WRITE_SUPPORT == Adapter->psFlash2xCSInfo->FlashWriteSupportSize)) { + Adapter->ulFlashWriteSize = Adapter->psFlash2xCSInfo->FlashWriteSupportSize; + Adapter->fpFlashWrite = flashByteWrite; + Adapter->fpFlashWriteWithStatusCheck = flashByteWriteStatus; + } else { + Adapter->ulFlashWriteSize = MAX_RW_SIZE; + Adapter->fpFlashWrite = flashWrite; + Adapter->fpFlashWriteWithStatusCheck = flashWriteStatus; + } + + BcmGetFlashSectorSize(Adapter, Adapter->psFlash2xCSInfo->FlashSectorSizeSig, + Adapter->psFlash2xCSInfo->FlashSectorSize); + + UpdateVendorInfo(Adapter); + + BcmGetActiveDSD(Adapter); + BcmGetActiveISO(Adapter); + Adapter->uiFlashBaseAdd = Adapter->psFlash2xCSInfo->FlashBaseAddr & 0xFCFFFFFF; + Adapter->ulFlashControlSectionStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForControlSectionStart; + } + /* + * Concerns: what if CS sector size does not match with this sector size ??? + * what is the indication of AccessBitMap in CS in flash 2.x ???? + */ + Adapter->ulFlashID = BcmReadFlashRDID(Adapter); + Adapter->uiFlashLayoutMajorVersion = uiFlashLayoutMajorVersion; + + return STATUS_SUCCESS; +} + +/* + * Procedure: BcmGetNvmType + * + * Description: Finds the type of NVM used. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * + * Returns: + * NVM_TYPE + * + */ + +static enum bcm_nvm_type BcmGetNvmType(struct bcm_mini_adapter *Adapter) +{ + unsigned int uiData = 0; + + BeceemEEPROMBulkRead(Adapter, &uiData, 0x0, 4); + if (uiData == BECM) + return NVM_EEPROM; + + /* + * Read control struct and get cal addresses before accessing the flash + */ + BcmGetFlashCSInfo(Adapter); + + BeceemFlashBulkRead(Adapter, &uiData, 0x0 + Adapter->ulFlashCalStart, 4); + if (uiData == BECM) + return NVM_FLASH; + + /* + * even if there is no valid signature on EEPROM/FLASH find out if they really exist. + * if exist select it. + */ + if (BcmGetEEPROMSize(Adapter)) + return NVM_EEPROM; + + /* TBD for Flash. */ + return NVM_UNKNOWN; +} + +/* + * BcmGetSectionValStartOffset - this will calculate the section's starting offset if section val is given + * @Adapter : Drivers Private Data structure + * @eFlashSectionVal : Flash secion value defined in enum bcm_flash2x_section_val + * + * Return value:- + * On success it return the start offset of the provided section val + * On Failure -returns STATUS_FAILURE + */ + +int BcmGetSectionValStartOffset(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlashSectionVal) +{ + /* + * Considering all the section for which end offset can be calculated or directly given + * in CS Structure. if matching case does not exist, return STATUS_FAILURE indicating section + * endoffset can't be calculated or given in CS Structure. + */ + + int SectStartOffset = 0; + + SectStartOffset = INVALID_OFFSET; + + if (IsSectionExistInVendorInfo(Adapter, eFlashSectionVal)) + return Adapter->psFlash2xVendorInfo->VendorSection[eFlashSectionVal].OffsetFromZeroForSectionStart; + + switch (eFlashSectionVal) { + case ISO_IMAGE1: + if ((Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start != UNINIT_PTR_IN_CS) && + (IsNonCDLessDevice(Adapter) == false)) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start); + break; + case ISO_IMAGE2: + if ((Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start != UNINIT_PTR_IN_CS) && + (IsNonCDLessDevice(Adapter) == false)) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start); + break; + case DSD0: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart != UNINIT_PTR_IN_CS) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart); + break; + case DSD1: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start != UNINIT_PTR_IN_CS) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start); + break; + case DSD2: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start != UNINIT_PTR_IN_CS) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start); + break; + case VSA0: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAStart != UNINIT_PTR_IN_CS) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAStart); + break; + case VSA1: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1Start != UNINIT_PTR_IN_CS) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1Start); + break; + case VSA2: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2Start != UNINIT_PTR_IN_CS) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2Start); + break; + case SCSI: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware != UNINIT_PTR_IN_CS) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware); + break; + case CONTROL_SECTION: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForControlSectionStart != UNINIT_PTR_IN_CS) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForControlSectionStart); + break; + case ISO_IMAGE1_PART2: + if (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start != UNINIT_PTR_IN_CS) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start); + break; + case ISO_IMAGE1_PART3: + if (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3Start != UNINIT_PTR_IN_CS) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3Start); + break; + case ISO_IMAGE2_PART2: + if (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start != UNINIT_PTR_IN_CS) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start); + break; + case ISO_IMAGE2_PART3: + if (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3Start != UNINIT_PTR_IN_CS) + SectStartOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3Start); + break; + default: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section Does not exist in Flash 2.x"); + SectStartOffset = INVALID_OFFSET; + } + + return SectStartOffset; +} + +/* + * BcmGetSectionValEndOffset - this will calculate the section's Ending offset if section val is given + * @Adapter : Drivers Private Data structure + * @eFlashSectionVal : Flash secion value defined in enum bcm_flash2x_section_val + * + * Return value:- + * On success it return the end offset of the provided section val + * On Failure -returns STATUS_FAILURE + */ + +static int BcmGetSectionValEndOffset(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectionVal) +{ + int SectEndOffset = 0; + + SectEndOffset = INVALID_OFFSET; + if (IsSectionExistInVendorInfo(Adapter, eFlash2xSectionVal)) + return Adapter->psFlash2xVendorInfo->VendorSection[eFlash2xSectionVal].OffsetFromZeroForSectionEnd; + + switch (eFlash2xSectionVal) { + case ISO_IMAGE1: + if ((Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End != UNINIT_PTR_IN_CS) && + (IsNonCDLessDevice(Adapter) == false)) + SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End); + break; + case ISO_IMAGE2: + if ((Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End != UNINIT_PTR_IN_CS) && + (IsNonCDLessDevice(Adapter) == false)) + SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End); + break; + case DSD0: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDEnd != UNINIT_PTR_IN_CS) + SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDEnd); + break; + case DSD1: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1End != UNINIT_PTR_IN_CS) + SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1End); + break; + case DSD2: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2End != UNINIT_PTR_IN_CS) + SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2End); + break; + case VSA0: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAEnd != UNINIT_PTR_IN_CS) + SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAEnd); + break; + case VSA1: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1End != UNINIT_PTR_IN_CS) + SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1End); + break; + case VSA2: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2End != UNINIT_PTR_IN_CS) + SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2End); + break; + case SCSI: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware != UNINIT_PTR_IN_CS) + SectEndOffset = ((Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware) + + (Adapter->psFlash2xCSInfo->SizeOfScsiFirmware)); + break; + case CONTROL_SECTION: + /* Not Clear So Putting failure. confirm and fix it. */ + SectEndOffset = STATUS_FAILURE; + break; + case ISO_IMAGE1_PART2: + if (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End != UNINIT_PTR_IN_CS) + SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End); + break; + case ISO_IMAGE1_PART3: + if (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3End != UNINIT_PTR_IN_CS) + SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3End); + break; + case ISO_IMAGE2_PART2: + if (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End != UNINIT_PTR_IN_CS) + SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End); + break; + case ISO_IMAGE2_PART3: + if (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3End != UNINIT_PTR_IN_CS) + SectEndOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3End); + break; + default: + SectEndOffset = INVALID_OFFSET; + } + + return SectEndOffset; +} + +/* + * BcmFlash2xBulkRead:- Read API for Flash Map 2.x . + * @Adapter :Driver Private Data Structure + * @pBuffer : Buffer where data has to be put after reading + * @eFlashSectionVal :Flash Section Val defined in enum bcm_flash2x_section_val + * @uiOffsetWithinSectionVal :- Offset with in provided section + * @uiNumBytes : Number of Bytes for Read + * + * Return value:- + * return true on success and STATUS_FAILURE on fail. + */ + +int BcmFlash2xBulkRead(struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + enum bcm_flash2x_section_val eFlash2xSectionVal, + unsigned int uiOffsetWithinSectionVal, + unsigned int uiNumBytes) +{ + int Status = STATUS_SUCCESS; + int SectionStartOffset = 0; + unsigned int uiAbsoluteOffset = 0; + unsigned int uiTemp = 0, value = 0; + + if (!Adapter) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Adapter structure is NULL"); + return -EINVAL; + } + if (Adapter->device_removed) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device has been removed"); + return -ENODEV; + } + + /* NO_SECTION_VAL means absolute offset is given. */ + if (eFlash2xSectionVal == NO_SECTION_VAL) + SectionStartOffset = 0; + else + SectionStartOffset = BcmGetSectionValStartOffset(Adapter, eFlash2xSectionVal); + + if (SectionStartOffset == STATUS_FAILURE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "This Section<%d> does not exist in Flash 2.x Map ", eFlash2xSectionVal); + return -EINVAL; + } + + if (IsSectionExistInVendorInfo(Adapter, eFlash2xSectionVal)) + return vendorextnReadSection(Adapter, (PUCHAR)pBuffer, eFlash2xSectionVal, uiOffsetWithinSectionVal, uiNumBytes); + + /* calculating the absolute offset from FLASH; */ + uiAbsoluteOffset = uiOffsetWithinSectionVal + SectionStartOffset; + rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp)); + value = 0; + wrmalt(Adapter, 0x0f000C80, &value, sizeof(value)); + Status = BeceemFlashBulkRead(Adapter, pBuffer, uiAbsoluteOffset, uiNumBytes); + wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Read Failed with Status :%d", Status); + return Status; + } + + return Status; +} + +/* + * BcmFlash2xBulkWrite :-API for Writing on the Flash Map 2.x. + * @Adapter :Driver Private Data Structure + * @pBuffer : Buffer From where data has to taken for writing + * @eFlashSectionVal :Flash Section Val defined in enum bcm_flash2x_section_val + * @uiOffsetWithinSectionVal :- Offset with in provided section + * @uiNumBytes : Number of Bytes for Write + * + * Return value:- + * return true on success and STATUS_FAILURE on fail. + * + */ + +int BcmFlash2xBulkWrite(struct bcm_mini_adapter *Adapter, + PUINT pBuffer, + enum bcm_flash2x_section_val eFlash2xSectVal, + unsigned int uiOffset, + unsigned int uiNumBytes, + unsigned int bVerify) +{ + int Status = STATUS_SUCCESS; + unsigned int FlashSectValStartOffset = 0; + unsigned int uiTemp = 0, value = 0; + + if (!Adapter) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Adapter structure is NULL"); + return -EINVAL; + } + + if (Adapter->device_removed) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Device has been removed"); + return -ENODEV; + } + + /* NO_SECTION_VAL means absolute offset is given. */ + if (eFlash2xSectVal == NO_SECTION_VAL) + FlashSectValStartOffset = 0; + else + FlashSectValStartOffset = BcmGetSectionValStartOffset(Adapter, eFlash2xSectVal); + + if (FlashSectValStartOffset == STATUS_FAILURE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "This Section<%d> does not exist in Flash Map 2.x", eFlash2xSectVal); + return -EINVAL; + } + + if (IsSectionExistInVendorInfo(Adapter, eFlash2xSectVal)) + return vendorextnWriteSection(Adapter, (PUCHAR)pBuffer, eFlash2xSectVal, uiOffset, uiNumBytes, bVerify); + + /* calculating the absolute offset from FLASH; */ + uiOffset = uiOffset + FlashSectValStartOffset; + + rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp)); + value = 0; + wrmalt(Adapter, 0x0f000C80, &value, sizeof(value)); + + Status = BeceemFlashBulkWrite(Adapter, pBuffer, uiOffset, uiNumBytes, bVerify); + + wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp)); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Flash Write failed with Status :%d", Status); + return Status; + } + + return Status; +} + +/* + * BcmGetActiveDSD : Set the Active DSD in Adapter Structure which has to be dumped in DDR + * @Adapter :-Drivers private Data Structure + * + * Return Value:- + * Return STATUS_SUCESS if get success in setting the right DSD else negative error code + * + */ + +static int BcmGetActiveDSD(struct bcm_mini_adapter *Adapter) +{ + enum bcm_flash2x_section_val uiHighestPriDSD = 0; + + uiHighestPriDSD = getHighestPriDSD(Adapter); + Adapter->eActiveDSD = uiHighestPriDSD; + + if (DSD0 == uiHighestPriDSD) + Adapter->ulFlashCalStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart; + if (DSD1 == uiHighestPriDSD) + Adapter->ulFlashCalStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start; + if (DSD2 == uiHighestPriDSD) + Adapter->ulFlashCalStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start; + if (Adapter->eActiveDSD) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Active DSD :%d", Adapter->eActiveDSD); + if (Adapter->eActiveDSD == 0) { + /* if No DSD gets Active, Make Active the DSD with WR permission */ + if (IsSectionWritable(Adapter, DSD2)) { + Adapter->eActiveDSD = DSD2; + Adapter->ulFlashCalStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start; + } else if (IsSectionWritable(Adapter, DSD1)) { + Adapter->eActiveDSD = DSD1; + Adapter->ulFlashCalStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start; + } else if (IsSectionWritable(Adapter, DSD0)) { + Adapter->eActiveDSD = DSD0; + Adapter->ulFlashCalStart = Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart; + } + } + + return STATUS_SUCCESS; +} + +/* + * BcmGetActiveISO :- Set the Active ISO in Adapter Data Structue + * @Adapter : Driver private Data Structure + * + * Return Value:- + * Sucsess:- STATUS_SUCESS + * Failure- : negative erro code + * + */ + +static int BcmGetActiveISO(struct bcm_mini_adapter *Adapter) +{ + int HighestPriISO = 0; + + HighestPriISO = getHighestPriISO(Adapter); + + Adapter->eActiveISO = HighestPriISO; + if (Adapter->eActiveISO == ISO_IMAGE2) + Adapter->uiActiveISOOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start); + else if (Adapter->eActiveISO == ISO_IMAGE1) + Adapter->uiActiveISOOffset = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start); + + if (Adapter->eActiveISO) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Active ISO :%x", Adapter->eActiveISO); + + return STATUS_SUCCESS; +} + +/* + * IsOffsetWritable :- it will tell the access permission of the sector having passed offset + * @Adapter : Drivers Private Data Structure + * @uiOffset : Offset provided in the Flash + * + * Return Value:- + * Success:-TRUE , offset is writable + * Failure:-false, offset is RO + * + */ + +static B_UINT8 IsOffsetWritable(struct bcm_mini_adapter *Adapter, unsigned int uiOffset) +{ + unsigned int uiSectorNum = 0; + unsigned int uiWordOfSectorPermission = 0; + unsigned int uiBitofSectorePermission = 0; + B_UINT32 permissionBits = 0; + + uiSectorNum = uiOffset/Adapter->uiSectorSize; + + /* calculating the word having this Sector Access permission from SectorAccessBitMap Array */ + uiWordOfSectorPermission = Adapter->psFlash2xCSInfo->SectorAccessBitMap[uiSectorNum / 16]; + + /* calculating the bit index inside the word for this sector */ + uiBitofSectorePermission = 2 * (15 - uiSectorNum % 16); + + /* Setting Access permission */ + permissionBits = uiWordOfSectorPermission & (0x3 << uiBitofSectorePermission); + permissionBits = (permissionBits >> uiBitofSectorePermission) & 0x3; + if (permissionBits == SECTOR_READWRITE_PERMISSION) + return TRUE; + else + return false; +} + +static int BcmDumpFlash2xSectionBitMap(struct bcm_flash2x_bitmap *psFlash2xBitMap) +{ + struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(gblpnetdev); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "***************Flash 2.x Section Bitmap***************"); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISO_IMAGE1 :0X%x", psFlash2xBitMap->ISO_IMAGE1); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISO_IMAGE2 :0X%x", psFlash2xBitMap->ISO_IMAGE2); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSD0 :0X%x", psFlash2xBitMap->DSD0); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSD1 :0X%x", psFlash2xBitMap->DSD1); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSD2 :0X%x", psFlash2xBitMap->DSD2); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "VSA0 :0X%x", psFlash2xBitMap->VSA0); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "VSA1 :0X%x", psFlash2xBitMap->VSA1); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "VSA2 :0X%x", psFlash2xBitMap->VSA2); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SCSI :0X%x", psFlash2xBitMap->SCSI); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "CONTROL_SECTION :0X%x", psFlash2xBitMap->CONTROL_SECTION); + + return STATUS_SUCCESS; +} + +/* + * BcmGetFlash2xSectionalBitMap :- It will provide the bit map of all the section present in Flash + * 8bit has been assigned to every section. + * bit[0] :Section present or not + * bit[1] :section is valid or not + * bit[2] : Secton is read only or has write permission too. + * bit[3] : Active Section - + * bit[7...4] = Reserved . + * + * @Adapter:-Driver private Data Structure + * + * Return value:- + * Success:- STATUS_SUCESS + * Failure:- negative error code + */ + +int BcmGetFlash2xSectionalBitMap(struct bcm_mini_adapter *Adapter, struct bcm_flash2x_bitmap *psFlash2xBitMap) +{ + struct bcm_flash2x_cs_info *psFlash2xCSInfo = Adapter->psFlash2xCSInfo; + enum bcm_flash2x_section_val uiHighestPriDSD = 0; + enum bcm_flash2x_section_val uiHighestPriISO = 0; + bool SetActiveDSDDone = false; + bool SetActiveISODone = false; + + /* For 1.x map all the section except DSD0 will be shown as not present + * This part will be used by calibration tool to detect the number of DSD present in Flash. + */ + if (IsFlash2x(Adapter) == false) { + psFlash2xBitMap->ISO_IMAGE2 = 0; + psFlash2xBitMap->ISO_IMAGE1 = 0; + psFlash2xBitMap->DSD0 = FLASH2X_SECTION_VALID | FLASH2X_SECTION_ACT | FLASH2X_SECTION_PRESENT; /* 0xF; 0000(Reseved)1(Active)0(RW)1(valid)1(present) */ + psFlash2xBitMap->DSD1 = 0; + psFlash2xBitMap->DSD2 = 0; + psFlash2xBitMap->VSA0 = 0; + psFlash2xBitMap->VSA1 = 0; + psFlash2xBitMap->VSA2 = 0; + psFlash2xBitMap->CONTROL_SECTION = 0; + psFlash2xBitMap->SCSI = 0; + psFlash2xBitMap->Reserved0 = 0; + psFlash2xBitMap->Reserved1 = 0; + psFlash2xBitMap->Reserved2 = 0; + + return STATUS_SUCCESS; + } + + uiHighestPriDSD = getHighestPriDSD(Adapter); + uiHighestPriISO = getHighestPriISO(Adapter); + + /* + * IS0 IMAGE 2 + */ + if ((psFlash2xCSInfo->OffsetISOImage2Part1Start) != UNINIT_PTR_IN_CS) { + /* Setting the 0th Bit representing the Section is present or not. */ + psFlash2xBitMap->ISO_IMAGE2 = psFlash2xBitMap->ISO_IMAGE2 | FLASH2X_SECTION_PRESENT; + + if (ReadISOSignature(Adapter, ISO_IMAGE2) == ISO_IMAGE_MAGIC_NUMBER) + psFlash2xBitMap->ISO_IMAGE2 |= FLASH2X_SECTION_VALID; + + /* Calculation for extrating the Access permission */ + if (IsSectionWritable(Adapter, ISO_IMAGE2) == false) + psFlash2xBitMap->ISO_IMAGE2 |= FLASH2X_SECTION_RO; + + if (SetActiveISODone == false && uiHighestPriISO == ISO_IMAGE2) { + psFlash2xBitMap->ISO_IMAGE2 |= FLASH2X_SECTION_ACT; + SetActiveISODone = TRUE; + } + } + + /* + * IS0 IMAGE 1 + */ + if ((psFlash2xCSInfo->OffsetISOImage1Part1Start) != UNINIT_PTR_IN_CS) { + /* Setting the 0th Bit representing the Section is present or not. */ + psFlash2xBitMap->ISO_IMAGE1 = psFlash2xBitMap->ISO_IMAGE1 | FLASH2X_SECTION_PRESENT; + + if (ReadISOSignature(Adapter, ISO_IMAGE1) == ISO_IMAGE_MAGIC_NUMBER) + psFlash2xBitMap->ISO_IMAGE1 |= FLASH2X_SECTION_VALID; + + /* Calculation for extrating the Access permission */ + if (IsSectionWritable(Adapter, ISO_IMAGE1) == false) + psFlash2xBitMap->ISO_IMAGE1 |= FLASH2X_SECTION_RO; + + if (SetActiveISODone == false && uiHighestPriISO == ISO_IMAGE1) { + psFlash2xBitMap->ISO_IMAGE1 |= FLASH2X_SECTION_ACT; + SetActiveISODone = TRUE; + } + } + + /* + * DSD2 + */ + if ((psFlash2xCSInfo->OffsetFromZeroForDSD2Start) != UNINIT_PTR_IN_CS) { + /* Setting the 0th Bit representing the Section is present or not. */ + psFlash2xBitMap->DSD2 = psFlash2xBitMap->DSD2 | FLASH2X_SECTION_PRESENT; + + if (ReadDSDSignature(Adapter, DSD2) == DSD_IMAGE_MAGIC_NUMBER) + psFlash2xBitMap->DSD2 |= FLASH2X_SECTION_VALID; + + /* Calculation for extrating the Access permission */ + if (IsSectionWritable(Adapter, DSD2) == false) { + psFlash2xBitMap->DSD2 |= FLASH2X_SECTION_RO; + } else { + /* Means section is writable */ + if ((SetActiveDSDDone == false) && (uiHighestPriDSD == DSD2)) { + psFlash2xBitMap->DSD2 |= FLASH2X_SECTION_ACT; + SetActiveDSDDone = TRUE; + } + } + } + + /* + * DSD 1 + */ + if ((psFlash2xCSInfo->OffsetFromZeroForDSD1Start) != UNINIT_PTR_IN_CS) { + /* Setting the 0th Bit representing the Section is present or not. */ + psFlash2xBitMap->DSD1 = psFlash2xBitMap->DSD1 | FLASH2X_SECTION_PRESENT; + + if (ReadDSDSignature(Adapter, DSD1) == DSD_IMAGE_MAGIC_NUMBER) + psFlash2xBitMap->DSD1 |= FLASH2X_SECTION_VALID; + + /* Calculation for extrating the Access permission */ + if (IsSectionWritable(Adapter, DSD1) == false) { + psFlash2xBitMap->DSD1 |= FLASH2X_SECTION_RO; + } else { + /* Means section is writable */ + if ((SetActiveDSDDone == false) && (uiHighestPriDSD == DSD1)) { + psFlash2xBitMap->DSD1 |= FLASH2X_SECTION_ACT; + SetActiveDSDDone = TRUE; + } + } + } + + /* + * For DSD 0 + */ + if ((psFlash2xCSInfo->OffsetFromZeroForDSDStart) != UNINIT_PTR_IN_CS) { + /* Setting the 0th Bit representing the Section is present or not. */ + psFlash2xBitMap->DSD0 = psFlash2xBitMap->DSD0 | FLASH2X_SECTION_PRESENT; + + if (ReadDSDSignature(Adapter, DSD0) == DSD_IMAGE_MAGIC_NUMBER) + psFlash2xBitMap->DSD0 |= FLASH2X_SECTION_VALID; + + /* Setting Access permission */ + if (IsSectionWritable(Adapter, DSD0) == false) { + psFlash2xBitMap->DSD0 |= FLASH2X_SECTION_RO; + } else { + /* Means section is writable */ + if ((SetActiveDSDDone == false) && (uiHighestPriDSD == DSD0)) { + psFlash2xBitMap->DSD0 |= FLASH2X_SECTION_ACT; + SetActiveDSDDone = TRUE; + } + } + } + + /* + * VSA 0 + */ + if ((psFlash2xCSInfo->OffsetFromZeroForVSAStart) != UNINIT_PTR_IN_CS) { + /* Setting the 0th Bit representing the Section is present or not. */ + psFlash2xBitMap->VSA0 = psFlash2xBitMap->VSA0 | FLASH2X_SECTION_PRESENT; + + /* Setting the Access Bit. Map is not defined hece setting it always valid */ + psFlash2xBitMap->VSA0 |= FLASH2X_SECTION_VALID; + + /* Calculation for extrating the Access permission */ + if (IsSectionWritable(Adapter, VSA0) == false) + psFlash2xBitMap->VSA0 |= FLASH2X_SECTION_RO; + + /* By Default section is Active */ + psFlash2xBitMap->VSA0 |= FLASH2X_SECTION_ACT; + } + + /* + * VSA 1 + */ + if ((psFlash2xCSInfo->OffsetFromZeroForVSA1Start) != UNINIT_PTR_IN_CS) { + /* Setting the 0th Bit representing the Section is present or not. */ + psFlash2xBitMap->VSA1 = psFlash2xBitMap->VSA1 | FLASH2X_SECTION_PRESENT; + + /* Setting the Access Bit. Map is not defined hece setting it always valid */ + psFlash2xBitMap->VSA1 |= FLASH2X_SECTION_VALID; + + /* Checking For Access permission */ + if (IsSectionWritable(Adapter, VSA1) == false) + psFlash2xBitMap->VSA1 |= FLASH2X_SECTION_RO; + + /* By Default section is Active */ + psFlash2xBitMap->VSA1 |= FLASH2X_SECTION_ACT; + } + + /* + * VSA 2 + */ + if ((psFlash2xCSInfo->OffsetFromZeroForVSA2Start) != UNINIT_PTR_IN_CS) { + /* Setting the 0th Bit representing the Section is present or not. */ + psFlash2xBitMap->VSA2 = psFlash2xBitMap->VSA2 | FLASH2X_SECTION_PRESENT; + + /* Setting the Access Bit. Map is not defined hece setting it always valid */ + psFlash2xBitMap->VSA2 |= FLASH2X_SECTION_VALID; + + /* Checking For Access permission */ + if (IsSectionWritable(Adapter, VSA2) == false) + psFlash2xBitMap->VSA2 |= FLASH2X_SECTION_RO; + + /* By Default section is Active */ + psFlash2xBitMap->VSA2 |= FLASH2X_SECTION_ACT; + } + + /* + * SCSI Section + */ + if ((psFlash2xCSInfo->OffsetFromZeroForScsiFirmware) != UNINIT_PTR_IN_CS) { + /* Setting the 0th Bit representing the Section is present or not. */ + psFlash2xBitMap->SCSI = psFlash2xBitMap->SCSI | FLASH2X_SECTION_PRESENT; + + /* Setting the Access Bit. Map is not defined hece setting it always valid */ + psFlash2xBitMap->SCSI |= FLASH2X_SECTION_VALID; + + /* Checking For Access permission */ + if (IsSectionWritable(Adapter, SCSI) == false) + psFlash2xBitMap->SCSI |= FLASH2X_SECTION_RO; + + /* By Default section is Active */ + psFlash2xBitMap->SCSI |= FLASH2X_SECTION_ACT; + } + + /* + * Control Section + */ + if ((psFlash2xCSInfo->OffsetFromZeroForControlSectionStart) != UNINIT_PTR_IN_CS) { + /* Setting the 0th Bit representing the Section is present or not. */ + psFlash2xBitMap->CONTROL_SECTION = psFlash2xBitMap->CONTROL_SECTION | (FLASH2X_SECTION_PRESENT); + + /* Setting the Access Bit. Map is not defined hece setting it always valid */ + psFlash2xBitMap->CONTROL_SECTION |= FLASH2X_SECTION_VALID; + + /* Checking For Access permission */ + if (IsSectionWritable(Adapter, CONTROL_SECTION) == false) + psFlash2xBitMap->CONTROL_SECTION |= FLASH2X_SECTION_RO; + + /* By Default section is Active */ + psFlash2xBitMap->CONTROL_SECTION |= FLASH2X_SECTION_ACT; + } + + /* + * For Reserved Sections + */ + psFlash2xBitMap->Reserved0 = 0; + psFlash2xBitMap->Reserved0 = 0; + psFlash2xBitMap->Reserved0 = 0; + BcmDumpFlash2xSectionBitMap(psFlash2xBitMap); + + return STATUS_SUCCESS; +} + +/* + * BcmSetActiveSection :- Set Active section is used to make priority field highest over other + * section of same type. + * + * @Adapater :- Bcm Driver Private Data Structure + * @eFlash2xSectionVal :- Flash section val whose priority has to be made highest. + * + * Return Value:- Make the priorit highest else return erorr code + * + */ + +int BcmSetActiveSection(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectVal) +{ + unsigned int SectImagePriority = 0; + int Status = STATUS_SUCCESS; + + /* struct bcm_dsd_header sDSD = {0}; + * struct bcm_iso_header sISO = {0}; + */ + int HighestPriDSD = 0; + int HighestPriISO = 0; + + Status = IsSectionWritable(Adapter, eFlash2xSectVal); + if (Status != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Provided Section <%d> is not writable", eFlash2xSectVal); + return STATUS_FAILURE; + } + + Adapter->bHeaderChangeAllowed = TRUE; + switch (eFlash2xSectVal) { + case ISO_IMAGE1: + case ISO_IMAGE2: + if (ReadISOSignature(Adapter, eFlash2xSectVal) == ISO_IMAGE_MAGIC_NUMBER) { + HighestPriISO = getHighestPriISO(Adapter); + + if (HighestPriISO == eFlash2xSectVal) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Given ISO<%x> already has highest priority", eFlash2xSectVal); + Status = STATUS_SUCCESS; + break; + } + + SectImagePriority = ReadISOPriority(Adapter, HighestPriISO) + 1; + + if ((SectImagePriority <= 0) && IsSectionWritable(Adapter, HighestPriISO)) { + /* This is a SPECIAL Case which will only happen if the current highest priority ISO has priority value = 0x7FFFFFFF. + * We will write 1 to the current Highest priority ISO And then shall increase the priority of the requested ISO + * by user + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "SectImagePriority wraparound happened, eFlash2xSectVal: 0x%x\n", eFlash2xSectVal); + SectImagePriority = htonl(0x1); + Status = BcmFlash2xBulkWrite(Adapter, + &SectImagePriority, + HighestPriISO, + 0 + FIELD_OFFSET_IN_HEADER(struct bcm_iso_header *, ISOImagePriority), + SIGNATURE_SIZE, + TRUE); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Priority has not been written properly"); + Status = STATUS_FAILURE; + break; + } + + HighestPriISO = getHighestPriISO(Adapter); + + if (HighestPriISO == eFlash2xSectVal) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Given ISO<%x> already has highest priority", eFlash2xSectVal); + Status = STATUS_SUCCESS; + break; + } + + SectImagePriority = 2; + } + + SectImagePriority = htonl(SectImagePriority); + + Status = BcmFlash2xBulkWrite(Adapter, + &SectImagePriority, + eFlash2xSectVal, + 0 + FIELD_OFFSET_IN_HEADER(struct bcm_iso_header *, ISOImagePriority), + SIGNATURE_SIZE, + TRUE); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Priority has not been written properly"); + break; + } + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Signature is currupted. Hence can't increase the priority"); + Status = STATUS_FAILURE; + break; + } + break; + case DSD0: + case DSD1: + case DSD2: + if (ReadDSDSignature(Adapter, eFlash2xSectVal) == DSD_IMAGE_MAGIC_NUMBER) { + HighestPriDSD = getHighestPriDSD(Adapter); + if (HighestPriDSD == eFlash2xSectVal) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Given DSD<%x> already has highest priority", eFlash2xSectVal); + Status = STATUS_SUCCESS; + break; + } + + SectImagePriority = ReadDSDPriority(Adapter, HighestPriDSD) + 1; + if (SectImagePriority <= 0) { + /* This is a SPECIAL Case which will only happen if the current highest priority DSD has priority value = 0x7FFFFFFF. + * We will write 1 to the current Highest priority DSD And then shall increase the priority of the requested DSD + * by user + */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, NVM_RW, DBG_LVL_ALL, "SectImagePriority wraparound happened, eFlash2xSectVal: 0x%x\n", eFlash2xSectVal); + SectImagePriority = htonl(0x1); + + Status = BcmFlash2xBulkWrite(Adapter, + &SectImagePriority, + HighestPriDSD, + Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(struct bcm_dsd_header *, DSDImagePriority), + SIGNATURE_SIZE, + TRUE); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Priority has not been written properly"); + break; + } + + HighestPriDSD = getHighestPriDSD(Adapter); + + if (HighestPriDSD == eFlash2xSectVal) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Made the DSD: %x highest by reducing priority of other\n", eFlash2xSectVal); + Status = STATUS_SUCCESS; + break; + } + + SectImagePriority = htonl(0x2); + Status = BcmFlash2xBulkWrite(Adapter, + &SectImagePriority, + HighestPriDSD, + Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(struct bcm_dsd_header *, DSDImagePriority), + SIGNATURE_SIZE, + TRUE); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Priority has not been written properly"); + break; + } + + HighestPriDSD = getHighestPriDSD(Adapter); + if (HighestPriDSD == eFlash2xSectVal) { + Status = STATUS_SUCCESS; + break; + } + + SectImagePriority = 3; + } + SectImagePriority = htonl(SectImagePriority); + Status = BcmFlash2xBulkWrite(Adapter, + &SectImagePriority, + eFlash2xSectVal, + Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(struct bcm_dsd_header *, DSDImagePriority), + SIGNATURE_SIZE, + TRUE); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Priority has not been written properly"); + Status = STATUS_FAILURE; + break; + } + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Signature is currupted. Hence can't increase the priority"); + Status = STATUS_FAILURE; + break; + } + break; + case VSA0: + case VSA1: + case VSA2: + /* Has to be decided */ + break; + default: + Status = STATUS_FAILURE; + break; + } + + Adapter->bHeaderChangeAllowed = false; + return Status; +} + +/* + * BcmCopyISO - Used only for copying the ISO section + * @Adapater :- Bcm Driver Private Data Structure + * @sCopySectStrut :- Section copy structure + * + * Return value:- SUCCESS if copies successfully else negative error code + * + */ + +int BcmCopyISO(struct bcm_mini_adapter *Adapter, struct bcm_flash2x_copy_section sCopySectStrut) +{ + PCHAR Buff = NULL; + enum bcm_flash2x_section_val eISOReadPart = 0, eISOWritePart = 0; + unsigned int uiReadOffsetWithinPart = 0, uiWriteOffsetWithinPart = 0; + unsigned int uiTotalDataToCopy = 0; + bool IsThisHeaderSector = false; + unsigned int sigOffset = 0; + unsigned int ISOLength = 0; + unsigned int Status = STATUS_SUCCESS; + unsigned int SigBuff[MAX_RW_SIZE]; + unsigned int i = 0; + + if (ReadISOSignature(Adapter, sCopySectStrut.SrcSection) != ISO_IMAGE_MAGIC_NUMBER) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "error as Source ISO Section does not have valid signature"); + return STATUS_FAILURE; + } + + Status = BcmFlash2xBulkRead(Adapter, + &ISOLength, + sCopySectStrut.SrcSection, + 0 + FIELD_OFFSET_IN_HEADER(struct bcm_iso_header *, ISOImageSize), + 4); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Read failed while copying ISO\n"); + return Status; + } + + ISOLength = htonl(ISOLength); + if (ISOLength % Adapter->uiSectorSize) + ISOLength = Adapter->uiSectorSize * (1 + ISOLength/Adapter->uiSectorSize); + + sigOffset = FIELD_OFFSET_IN_HEADER(struct bcm_iso_header *, ISOImageMagicNumber); + + Buff = kzalloc(Adapter->uiSectorSize, GFP_KERNEL); + + if (!Buff) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed for section size"); + return -ENOMEM; + } + + if (sCopySectStrut.SrcSection == ISO_IMAGE1 && sCopySectStrut.DstSection == ISO_IMAGE2) { + eISOReadPart = ISO_IMAGE1; + eISOWritePart = ISO_IMAGE2; + uiReadOffsetWithinPart = 0; + uiWriteOffsetWithinPart = 0; + + uiTotalDataToCopy = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End) - + (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start) + + (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End) - + (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start) + + (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3End) - + (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3Start); + + if (uiTotalDataToCopy < ISOLength) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "error as Source ISO Section does not have valid signature"); + Status = STATUS_FAILURE; + goto out; + } + + uiTotalDataToCopy = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End) - + (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start) + + (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End) - + (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start) + + (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3End) - + (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3Start); + + if (uiTotalDataToCopy < ISOLength) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "error as Dest ISO Section does not have enough section size"); + Status = STATUS_FAILURE; + goto out; + } + + uiTotalDataToCopy = ISOLength; + + CorruptISOSig(Adapter, ISO_IMAGE2); + while (uiTotalDataToCopy) { + if (uiTotalDataToCopy == Adapter->uiSectorSize) { + /* Setting for write of first sector. First sector is assumed to be written in last */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Writing the signature sector"); + eISOReadPart = ISO_IMAGE1; + uiReadOffsetWithinPart = 0; + eISOWritePart = ISO_IMAGE2; + uiWriteOffsetWithinPart = 0; + IsThisHeaderSector = TRUE; + } else { + uiReadOffsetWithinPart = uiReadOffsetWithinPart + Adapter->uiSectorSize; + uiWriteOffsetWithinPart = uiWriteOffsetWithinPart + Adapter->uiSectorSize; + + if ((eISOReadPart == ISO_IMAGE1) && (uiReadOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End - Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start))) { + eISOReadPart = ISO_IMAGE1_PART2; + uiReadOffsetWithinPart = 0; + } + + if ((eISOReadPart == ISO_IMAGE1_PART2) && (uiReadOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End - Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start))) { + eISOReadPart = ISO_IMAGE1_PART3; + uiReadOffsetWithinPart = 0; + } + + if ((eISOWritePart == ISO_IMAGE2) && (uiWriteOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End - Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start))) { + eISOWritePart = ISO_IMAGE2_PART2; + uiWriteOffsetWithinPart = 0; + } + + if ((eISOWritePart == ISO_IMAGE2_PART2) && (uiWriteOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End - Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start))) { + eISOWritePart = ISO_IMAGE2_PART3; + uiWriteOffsetWithinPart = 0; + } + } + + Status = BcmFlash2xBulkRead(Adapter, + (PUINT)Buff, + eISOReadPart, + uiReadOffsetWithinPart, + Adapter->uiSectorSize); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Read failed while copying ISO: Part: %x, OffsetWithinPart: %x\n", eISOReadPart, uiReadOffsetWithinPart); + break; + } + + if (IsThisHeaderSector == TRUE) { + /* If this is header sector write 0xFFFFFFFF at the sig time and in last write sig */ + memcpy(SigBuff, Buff + sigOffset, MAX_RW_SIZE); + + for (i = 0; i < MAX_RW_SIZE; i++) + *(Buff + sigOffset + i) = 0xFF; + } + Adapter->bHeaderChangeAllowed = TRUE; + Status = BcmFlash2xBulkWrite(Adapter, + (PUINT)Buff, + eISOWritePart, + uiWriteOffsetWithinPart, + Adapter->uiSectorSize, + TRUE); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write failed while copying ISO: Part: %x, OffsetWithinPart: %x\n", eISOWritePart, uiWriteOffsetWithinPart); + break; + } + + Adapter->bHeaderChangeAllowed = false; + if (IsThisHeaderSector == TRUE) { + WriteToFlashWithoutSectorErase(Adapter, + SigBuff, + eISOWritePart, + sigOffset, + MAX_RW_SIZE); + IsThisHeaderSector = false; + } + /* subtracting the written Data */ + uiTotalDataToCopy = uiTotalDataToCopy - Adapter->uiSectorSize; + } + } + + if (sCopySectStrut.SrcSection == ISO_IMAGE2 && sCopySectStrut.DstSection == ISO_IMAGE1) { + eISOReadPart = ISO_IMAGE2; + eISOWritePart = ISO_IMAGE1; + uiReadOffsetWithinPart = 0; + uiWriteOffsetWithinPart = 0; + + uiTotalDataToCopy = (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End) - + (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start) + + (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End) - + (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start) + + (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3End) - + (Adapter->psFlash2xCSInfo->OffsetISOImage2Part3Start); + + if (uiTotalDataToCopy < ISOLength) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "error as Source ISO Section does not have valid signature"); + Status = STATUS_FAILURE; + goto out; + } + + uiTotalDataToCopy = (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End) - + (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start) + + (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End) - + (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start) + + (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3End) - + (Adapter->psFlash2xCSInfo->OffsetISOImage1Part3Start); + + if (uiTotalDataToCopy < ISOLength) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "error as Dest ISO Section does not have enough section size"); + Status = STATUS_FAILURE; + goto out; + } + + uiTotalDataToCopy = ISOLength; + + CorruptISOSig(Adapter, ISO_IMAGE1); + + while (uiTotalDataToCopy) { + if (uiTotalDataToCopy == Adapter->uiSectorSize) { + /* Setting for write of first sector. First sector is assumed to be written in last */ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Writing the signature sector"); + eISOReadPart = ISO_IMAGE2; + uiReadOffsetWithinPart = 0; + eISOWritePart = ISO_IMAGE1; + uiWriteOffsetWithinPart = 0; + IsThisHeaderSector = TRUE; + } else { + uiReadOffsetWithinPart = uiReadOffsetWithinPart + Adapter->uiSectorSize; + uiWriteOffsetWithinPart = uiWriteOffsetWithinPart + Adapter->uiSectorSize; + + if ((eISOReadPart == ISO_IMAGE2) && (uiReadOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage2Part1End - Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start))) { + eISOReadPart = ISO_IMAGE2_PART2; + uiReadOffsetWithinPart = 0; + } + + if ((eISOReadPart == ISO_IMAGE2_PART2) && (uiReadOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage2Part2End - Adapter->psFlash2xCSInfo->OffsetISOImage2Part2Start))) { + eISOReadPart = ISO_IMAGE2_PART3; + uiReadOffsetWithinPart = 0; + } + + if ((eISOWritePart == ISO_IMAGE1) && (uiWriteOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage1Part1End - Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start))) { + eISOWritePart = ISO_IMAGE1_PART2; + uiWriteOffsetWithinPart = 0; + } + + if ((eISOWritePart == ISO_IMAGE1_PART2) && (uiWriteOffsetWithinPart == (Adapter->psFlash2xCSInfo->OffsetISOImage1Part2End - Adapter->psFlash2xCSInfo->OffsetISOImage1Part2Start))) { + eISOWritePart = ISO_IMAGE1_PART3; + uiWriteOffsetWithinPart = 0; + } + } + + Status = BcmFlash2xBulkRead(Adapter, + (PUINT)Buff, + eISOReadPart, + uiReadOffsetWithinPart, + Adapter->uiSectorSize); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Read failed while copying ISO: Part: %x, OffsetWithinPart: %x\n", eISOReadPart, uiReadOffsetWithinPart); + break; + } + + if (IsThisHeaderSector == TRUE) { + /* If this is header sector write 0xFFFFFFFF at the sig time and in last write sig */ + memcpy(SigBuff, Buff + sigOffset, MAX_RW_SIZE); + + for (i = 0; i < MAX_RW_SIZE; i++) + *(Buff + sigOffset + i) = 0xFF; + } + Adapter->bHeaderChangeAllowed = TRUE; + Status = BcmFlash2xBulkWrite(Adapter, + (PUINT)Buff, + eISOWritePart, + uiWriteOffsetWithinPart, + Adapter->uiSectorSize, + TRUE); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write failed while copying ISO: Part: %x, OffsetWithinPart: %x\n", eISOWritePart, uiWriteOffsetWithinPart); + break; + } + + Adapter->bHeaderChangeAllowed = false; + if (IsThisHeaderSector == TRUE) { + WriteToFlashWithoutSectorErase(Adapter, + SigBuff, + eISOWritePart, + sigOffset, + MAX_RW_SIZE); + + IsThisHeaderSector = false; + } + + /* subtracting the written Data */ + uiTotalDataToCopy = uiTotalDataToCopy - Adapter->uiSectorSize; + } + } +out: + kfree(Buff); + + return Status; +} + +/* + * BcmFlash2xCorruptSig : this API is used to corrupt the written sig in Bcm Header present in flash section. + * It will corrupt the sig, if Section is writable, by making first bytes as zero. + * @Adapater :- Bcm Driver Private Data Structure + * @eFlash2xSectionVal :- Flash section val which has header + * + * Return Value :- + * Success :- If Section is present and writable, corrupt the sig and return STATUS_SUCCESS + * Failure :-Return negative error code + */ + +int BcmFlash2xCorruptSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectionVal) +{ + int Status = STATUS_SUCCESS; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section Value :%x\n", eFlash2xSectionVal); + + if ((eFlash2xSectionVal == DSD0) || (eFlash2xSectionVal == DSD1) || (eFlash2xSectionVal == DSD2)) { + Status = CorruptDSDSig(Adapter, eFlash2xSectionVal); + } else if (eFlash2xSectionVal == ISO_IMAGE1 || eFlash2xSectionVal == ISO_IMAGE2) { + Status = CorruptISOSig(Adapter, eFlash2xSectionVal); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Given Section <%d>does not have Header", eFlash2xSectionVal); + return STATUS_SUCCESS; + } + return Status; +} + +/* + *BcmFlash2xWriteSig :-this API is used to Write the sig if requested Section has + * header and Write Permission. + * @Adapater :- Bcm Driver Private Data Structure + * @eFlashSectionVal :- Flash section val which has header + * + * Return Value :- + * Success :- If Section is present and writable write the sig and return STATUS_SUCCESS + * Failure :-Return negative error code + */ + +int BcmFlash2xWriteSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlashSectionVal) +{ + unsigned int uiSignature = 0; + unsigned int uiOffset = 0; + + /* struct bcm_dsd_header dsdHeader = {0}; */ + if (Adapter->bSigCorrupted == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Signature is not corrupted by driver, hence not restoring\n"); + return STATUS_SUCCESS; + } + + if (Adapter->bAllDSDWriteAllow == false) { + if (IsSectionWritable(Adapter, eFlashSectionVal) == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section is not Writable...Hence can't Write signature"); + return SECTOR_IS_NOT_WRITABLE; + } + } + + if ((eFlashSectionVal == DSD0) || (eFlashSectionVal == DSD1) || (eFlashSectionVal == DSD2)) { + uiSignature = htonl(DSD_IMAGE_MAGIC_NUMBER); + uiOffset = Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader; + + uiOffset += FIELD_OFFSET_IN_HEADER(struct bcm_dsd_header *, DSDImageMagicNumber); + + if ((ReadDSDSignature(Adapter, eFlashSectionVal) & 0xFF000000) != CORRUPTED_PATTERN) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Corrupted Pattern is not there. Hence won't write sig"); + return STATUS_FAILURE; + } + } else if ((eFlashSectionVal == ISO_IMAGE1) || (eFlashSectionVal == ISO_IMAGE2)) { + uiSignature = htonl(ISO_IMAGE_MAGIC_NUMBER); + /* uiOffset = 0; */ + uiOffset = FIELD_OFFSET_IN_HEADER(struct bcm_iso_header *, ISOImageMagicNumber); + if ((ReadISOSignature(Adapter, eFlashSectionVal) & 0xFF000000) != CORRUPTED_PATTERN) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Currupted Pattern is not there. Hence won't write sig"); + return STATUS_FAILURE; + } + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "GIVEN SECTION< %d > IS NOT VALID FOR SIG WRITE...", eFlashSectionVal); + return STATUS_FAILURE; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Restoring the signature"); + + Adapter->bHeaderChangeAllowed = TRUE; + Adapter->bSigCorrupted = false; + BcmFlash2xBulkWrite(Adapter, &uiSignature, eFlashSectionVal, uiOffset, SIGNATURE_SIZE, TRUE); + Adapter->bHeaderChangeAllowed = false; + + return STATUS_SUCCESS; +} + +/* + * validateFlash2xReadWrite :- This API is used to validate the user request for Read/Write. + * if requested Bytes goes beyond the Requested section, it reports error. + * @Adapater :- Bcm Driver Private Data Structure + * @psFlash2xReadWrite :-Flash2x Read/write structure pointer + * + * Return values:-Return TRUE is request is valid else false. + */ + +int validateFlash2xReadWrite(struct bcm_mini_adapter *Adapter, struct bcm_flash2x_readwrite *psFlash2xReadWrite) +{ + unsigned int uiNumOfBytes = 0; + unsigned int uiSectStartOffset = 0; + unsigned int uiSectEndOffset = 0; + + uiNumOfBytes = psFlash2xReadWrite->numOfBytes; + + if (IsSectionExistInFlash(Adapter, psFlash2xReadWrite->Section) != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section<%x> does not exist in Flash", psFlash2xReadWrite->Section); + return false; + } + uiSectStartOffset = BcmGetSectionValStartOffset(Adapter, psFlash2xReadWrite->Section); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Start offset :%x ,section :%d\n", uiSectStartOffset, psFlash2xReadWrite->Section); + if ((psFlash2xReadWrite->Section == ISO_IMAGE1) || (psFlash2xReadWrite->Section == ISO_IMAGE2)) { + if (psFlash2xReadWrite->Section == ISO_IMAGE1) { + uiSectEndOffset = BcmGetSectionValEndOffset(Adapter, ISO_IMAGE1) - + BcmGetSectionValStartOffset(Adapter, ISO_IMAGE1) + + BcmGetSectionValEndOffset(Adapter, ISO_IMAGE1_PART2) - + BcmGetSectionValStartOffset(Adapter, ISO_IMAGE1_PART2) + + BcmGetSectionValEndOffset(Adapter, ISO_IMAGE1_PART3) - + BcmGetSectionValStartOffset(Adapter, ISO_IMAGE1_PART3); + } else if (psFlash2xReadWrite->Section == ISO_IMAGE2) { + uiSectEndOffset = BcmGetSectionValEndOffset(Adapter, ISO_IMAGE2) - + BcmGetSectionValStartOffset(Adapter, ISO_IMAGE2) + + BcmGetSectionValEndOffset(Adapter, ISO_IMAGE2_PART2) - + BcmGetSectionValStartOffset(Adapter, ISO_IMAGE2_PART2) + + BcmGetSectionValEndOffset(Adapter, ISO_IMAGE2_PART3) - + BcmGetSectionValStartOffset(Adapter, ISO_IMAGE2_PART3); + } + + /* since this uiSectEndoffset is the size of iso Image. hence for calculating the virtual endoffset + * it should be added in startoffset. so that check done in last of this function can be valued. + */ + uiSectEndOffset = uiSectStartOffset + uiSectEndOffset; + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Total size of the ISO Image :%x", uiSectEndOffset); + } else + uiSectEndOffset = BcmGetSectionValEndOffset(Adapter, psFlash2xReadWrite->Section); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "End offset :%x\n", uiSectEndOffset); + + /* psFlash2xReadWrite->offset and uiNumOfBytes are user controlled and can lead to integer overflows */ + if (psFlash2xReadWrite->offset > uiSectEndOffset) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Invalid Request...."); + return false; + } + if (uiNumOfBytes > uiSectEndOffset) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Invalid Request...."); + return false; + } + /* Checking the boundary condition */ + if ((uiSectStartOffset + psFlash2xReadWrite->offset + uiNumOfBytes) <= uiSectEndOffset) + return TRUE; + else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Invalid Request...."); + return false; + } +} + +/* + * IsFlash2x :- check for Flash 2.x + * Adapater :- Bcm Driver Private Data Structure + * + * Return value:- + * return TRUE if flah2.x of hgher version else return false. + */ + +int IsFlash2x(struct bcm_mini_adapter *Adapter) +{ + if (Adapter->uiFlashLayoutMajorVersion >= FLASH_2X_MAJOR_NUMBER) + return TRUE; + else + return false; +} + +/* + * GetFlashBaseAddr :- Calculate the Flash Base address + * @Adapater :- Bcm Driver Private Data Structure + * + * Return Value:- + * Success :- Base Address of the Flash + */ + +static int GetFlashBaseAddr(struct bcm_mini_adapter *Adapter) +{ + unsigned int uiBaseAddr = 0; + + if (Adapter->bDDRInitDone) { + /* + * For All Valid Flash Versions... except 1.1, take the value from FlashBaseAddr + * In case of Raw Read... use the default value + */ + if (Adapter->uiFlashLayoutMajorVersion && (Adapter->bFlashRawRead == false) && + !((Adapter->uiFlashLayoutMajorVersion == 1) && (Adapter->uiFlashLayoutMinorVersion == 1))) + uiBaseAddr = Adapter->uiFlashBaseAdd; + else + uiBaseAddr = FLASH_CONTIGIOUS_START_ADDR_AFTER_INIT; + } else { + /* + * For All Valid Flash Versions... except 1.1, take the value from FlashBaseAddr + * In case of Raw Read... use the default value + */ + if (Adapter->uiFlashLayoutMajorVersion && (Adapter->bFlashRawRead == false) && + !((Adapter->uiFlashLayoutMajorVersion == 1) && (Adapter->uiFlashLayoutMinorVersion == 1))) + uiBaseAddr = Adapter->uiFlashBaseAdd | FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT; + else + uiBaseAddr = FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT; + } + + return uiBaseAddr; +} + +/* + * BcmCopySection :- This API is used to copy the One section in another. Both section should + * be contiuous and of same size. Hence this Will not be applicabe to copy ISO. + * + * @Adapater :- Bcm Driver Private Data Structure + * @SrcSection :- Source section From where data has to be copied + * @DstSection :- Destination section to which data has to be copied + * @offset :- Offset from/to where data has to be copied from one section to another. + * @numOfBytes :- number of byes that has to be copyed from one section to another at given offset. + * in case of numofBytes equal zero complete section will be copied. + * Return Values- + * Success : Return STATUS_SUCCESS + * Faillure :- return negative error code + */ + +int BcmCopySection(struct bcm_mini_adapter *Adapter, + enum bcm_flash2x_section_val SrcSection, + enum bcm_flash2x_section_val DstSection, + unsigned int offset, + unsigned int numOfBytes) +{ + unsigned int BuffSize = 0; + unsigned int BytesToBeCopied = 0; + PUCHAR pBuff = NULL; + int Status = STATUS_SUCCESS; + + if (SrcSection == DstSection) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Source and Destination should be different ...try again"); + return -EINVAL; + } + + if ((SrcSection != DSD0) && (SrcSection != DSD1) && (SrcSection != DSD2)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Source should be DSD subsection"); + return -EINVAL; + } + + if ((DstSection != DSD0) && (DstSection != DSD1) && (DstSection != DSD2)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Destination should be DSD subsection"); + return -EINVAL; + } + + /* if offset zero means have to copy complete secton */ + if (numOfBytes == 0) { + numOfBytes = BcmGetSectionValEndOffset(Adapter, SrcSection) + - BcmGetSectionValStartOffset(Adapter, SrcSection); + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Section Size :0x%x", numOfBytes); + } + + if ((offset + numOfBytes) > BcmGetSectionValEndOffset(Adapter, SrcSection) + - BcmGetSectionValStartOffset(Adapter, SrcSection)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, " Input parameters going beyond the section offS: %x numB: %x of Source Section\n", + offset, numOfBytes); + return -EINVAL; + } + + if ((offset + numOfBytes) > BcmGetSectionValEndOffset(Adapter, DstSection) + - BcmGetSectionValStartOffset(Adapter, DstSection)) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Input parameters going beyond the section offS: %x numB: %x of Destination Section\n", + offset, numOfBytes); + return -EINVAL; + } + + if (numOfBytes > Adapter->uiSectorSize) + BuffSize = Adapter->uiSectorSize; + else + BuffSize = numOfBytes; + + pBuff = kzalloc(BuffSize, GFP_KERNEL); + if (!pBuff) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed.. "); + return -ENOMEM; + } + + BytesToBeCopied = Adapter->uiSectorSize; + if (offset % Adapter->uiSectorSize) + BytesToBeCopied = Adapter->uiSectorSize - (offset % Adapter->uiSectorSize); + if (BytesToBeCopied > numOfBytes) + BytesToBeCopied = numOfBytes; + + Adapter->bHeaderChangeAllowed = TRUE; + + do { + Status = BcmFlash2xBulkRead(Adapter, (PUINT)pBuff, SrcSection , offset, BytesToBeCopied); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Read failed at offset :%d for NOB :%d", SrcSection, BytesToBeCopied); + break; + } + Status = BcmFlash2xBulkWrite(Adapter, (PUINT)pBuff, DstSection, offset, BytesToBeCopied, false); + if (Status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Write failed at offset :%d for NOB :%d", DstSection, BytesToBeCopied); + break; + } + offset = offset + BytesToBeCopied; + numOfBytes = numOfBytes - BytesToBeCopied; + if (numOfBytes) { + if (numOfBytes > Adapter->uiSectorSize) + BytesToBeCopied = Adapter->uiSectorSize; + else + BytesToBeCopied = numOfBytes; + } + } while (numOfBytes > 0); + + kfree(pBuff); + Adapter->bHeaderChangeAllowed = false; + + return Status; +} + +/* + * SaveHeaderIfPresent :- This API is use to Protect the Header in case of Header Sector write + * @Adapater :- Bcm Driver Private Data Structure + * @pBuff :- Data buffer that has to be written in sector having the header map. + * @uiOffset :- Flash offset that has to be written. + * + * Return value :- + * Success :- On success return STATUS_SUCCESS + * Faillure :- Return negative error code + */ + +static int SaveHeaderIfPresent(struct bcm_mini_adapter *Adapter, PUCHAR pBuff, unsigned int uiOffset) +{ + unsigned int offsetToProtect = 0, HeaderSizeToProtect = 0; + bool bHasHeader = false; + PUCHAR pTempBuff = NULL; + unsigned int uiSectAlignAddr = 0; + unsigned int sig = 0; + + /* making the offset sector aligned */ + uiSectAlignAddr = uiOffset & ~(Adapter->uiSectorSize - 1); + + if ((uiSectAlignAddr == BcmGetSectionValEndOffset(Adapter, DSD2) - Adapter->uiSectorSize) || + (uiSectAlignAddr == BcmGetSectionValEndOffset(Adapter, DSD1) - Adapter->uiSectorSize) || + (uiSectAlignAddr == BcmGetSectionValEndOffset(Adapter, DSD0) - Adapter->uiSectorSize)) { + /* offset from the sector boundary having the header map */ + offsetToProtect = Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader % Adapter->uiSectorSize; + HeaderSizeToProtect = sizeof(struct bcm_dsd_header); + bHasHeader = TRUE; + } + + if (uiSectAlignAddr == BcmGetSectionValStartOffset(Adapter, ISO_IMAGE1) || + uiSectAlignAddr == BcmGetSectionValStartOffset(Adapter, ISO_IMAGE2)) { + offsetToProtect = 0; + HeaderSizeToProtect = sizeof(struct bcm_iso_header); + bHasHeader = TRUE; + } + /* If Header is present overwrite passed buffer with this */ + if (bHasHeader && (Adapter->bHeaderChangeAllowed == false)) { + pTempBuff = kzalloc(HeaderSizeToProtect, GFP_KERNEL); + if (!pTempBuff) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Memory allocation failed"); + return -ENOMEM; + } + /* Read header */ + BeceemFlashBulkRead(Adapter, (PUINT)pTempBuff, (uiSectAlignAddr + offsetToProtect), HeaderSizeToProtect); + BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, pTempBuff, HeaderSizeToProtect); + /* Replace Buffer content with Header */ + memcpy(pBuff + offsetToProtect, pTempBuff, HeaderSizeToProtect); + + kfree(pTempBuff); + } + if (bHasHeader && Adapter->bSigCorrupted) { + sig = *((PUINT)(pBuff + offsetToProtect + FIELD_OFFSET_IN_HEADER(struct bcm_dsd_header *, DSDImageMagicNumber))); + sig = ntohl(sig); + if ((sig & 0xFF000000) != CORRUPTED_PATTERN) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Desired pattern is not at sig offset. Hence won't restore"); + Adapter->bSigCorrupted = false; + return STATUS_SUCCESS; + } + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, " Corrupted sig is :%X", sig); + *((PUINT)(pBuff + offsetToProtect + FIELD_OFFSET_IN_HEADER(struct bcm_dsd_header *, DSDImageMagicNumber))) = htonl(DSD_IMAGE_MAGIC_NUMBER); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Restoring the signature in Header Write only"); + Adapter->bSigCorrupted = false; + } + + return STATUS_SUCCESS; +} + +/* + * BcmDoChipSelect : This will selcet the appropriate chip for writing. + * @Adapater :- Bcm Driver Private Data Structure + * + * OutPut:- + * Select the Appropriate chip and retrn status Success + */ +static int BcmDoChipSelect(struct bcm_mini_adapter *Adapter, unsigned int offset) +{ + unsigned int FlashConfig = 0; + int ChipNum = 0; + unsigned int GPIOConfig = 0; + unsigned int PartNum = 0; + + ChipNum = offset / FLASH_PART_SIZE; + + /* + * Chip Select mapping to enable flash0. + * To select flash 0, we have to OR with (0<<12). + * ORing 0 will have no impact so not doing that part. + * In future if Chip select value changes from 0 to non zero, + * That needs be taken care with backward comaptibility. No worries for now. + */ + + /* + * SelectedChip Variable is the selection that the host is 100% Sure the same as what the register will hold. This can be ONLY ensured + * if the Chip doesn't goes to low power mode while the flash operation is in progress (NVMRdmWrmLock is taken) + * Before every new Flash Write operation, we reset the variable. This is to ensure that after any wake-up from + * power down modes (Idle mode/shutdown mode), the values in the register will be different. + */ + + if (Adapter->SelectedChip == ChipNum) + return STATUS_SUCCESS; + + /* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Selected Chip :%x", ChipNum); */ + Adapter->SelectedChip = ChipNum; + + /* bit[13..12] will select the appropriate chip */ + rdmalt(Adapter, FLASH_CONFIG_REG, &FlashConfig, 4); + rdmalt(Adapter, FLASH_GPIO_CONFIG_REG, &GPIOConfig, 4); + { + switch (ChipNum) { + case 0: + PartNum = 0; + break; + case 1: + PartNum = 3; + GPIOConfig |= (0x4 << CHIP_SELECT_BIT12); + break; + case 2: + PartNum = 1; + GPIOConfig |= (0x1 << CHIP_SELECT_BIT12); + break; + case 3: + PartNum = 2; + GPIOConfig |= (0x2 << CHIP_SELECT_BIT12); + break; + } + } + /* In case the bits already written in the FLASH_CONFIG_REG is same as what the user desired, + * nothing to do... can return immediately. + * ASSUMPTION: FLASH_GPIO_CONFIG_REG will be in sync with FLASH_CONFIG_REG. + * Even if the chip goes to low power mode, it should wake with values in each register in sync with each other. + * These values are not written by host other than during CHIP_SELECT. + */ + if (PartNum == ((FlashConfig >> CHIP_SELECT_BIT12) & 0x3)) + return STATUS_SUCCESS; + + /* clearing the bit[13..12] */ + FlashConfig &= 0xFFFFCFFF; + FlashConfig = (FlashConfig | (PartNum<<CHIP_SELECT_BIT12)); /* 00 */ + + wrmalt(Adapter, FLASH_GPIO_CONFIG_REG, &GPIOConfig, 4); + udelay(100); + + wrmalt(Adapter, FLASH_CONFIG_REG, &FlashConfig, 4); + udelay(100); + + return STATUS_SUCCESS; +} + +static int ReadDSDSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val dsd) +{ + unsigned int uiDSDsig = 0; + /* unsigned int sigoffsetInMap = 0; + * struct bcm_dsd_header dsdHeader = {0}; + */ + + /* sigoffsetInMap =(PUCHAR)&(dsdHeader.DSDImageMagicNumber) -(PUCHAR)&dsdHeader; */ + + if (dsd != DSD0 && dsd != DSD1 && dsd != DSD2) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "passed section value is not for DSDs"); + return STATUS_FAILURE; + } + BcmFlash2xBulkRead(Adapter, + &uiDSDsig, + dsd, + Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(struct bcm_dsd_header *, DSDImageMagicNumber), + SIGNATURE_SIZE); + + uiDSDsig = ntohl(uiDSDsig); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSD SIG :%x", uiDSDsig); + + return uiDSDsig; +} + +static int ReadDSDPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val dsd) +{ + /* unsigned int priOffsetInMap = 0 ; */ + unsigned int uiDSDPri = STATUS_FAILURE; + /* struct bcm_dsd_header dsdHeader = {0}; + * priOffsetInMap = (PUCHAR)&(dsdHeader.DSDImagePriority) -(PUCHAR)&dsdHeader; + */ + if (IsSectionWritable(Adapter, dsd)) { + if (ReadDSDSignature(Adapter, dsd) == DSD_IMAGE_MAGIC_NUMBER) { + BcmFlash2xBulkRead(Adapter, + &uiDSDPri, + dsd, + Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + FIELD_OFFSET_IN_HEADER(struct bcm_dsd_header *, DSDImagePriority), + 4); + + uiDSDPri = ntohl(uiDSDPri); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "DSD<%x> Priority :%x", dsd, uiDSDPri); + } + } + + return uiDSDPri; +} + +static enum bcm_flash2x_section_val getHighestPriDSD(struct bcm_mini_adapter *Adapter) +{ + int DSDHighestPri = STATUS_FAILURE; + int DsdPri = 0; + enum bcm_flash2x_section_val HighestPriDSD = 0; + + if (IsSectionWritable(Adapter, DSD2)) { + DSDHighestPri = ReadDSDPriority(Adapter, DSD2); + HighestPriDSD = DSD2; + } + + if (IsSectionWritable(Adapter, DSD1)) { + DsdPri = ReadDSDPriority(Adapter, DSD1); + if (DSDHighestPri < DsdPri) { + DSDHighestPri = DsdPri; + HighestPriDSD = DSD1; + } + } + + if (IsSectionWritable(Adapter, DSD0)) { + DsdPri = ReadDSDPriority(Adapter, DSD0); + if (DSDHighestPri < DsdPri) { + DSDHighestPri = DsdPri; + HighestPriDSD = DSD0; + } + } + if (HighestPriDSD) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Highest DSD :%x , and its Pri :%x", HighestPriDSD, DSDHighestPri); + + return HighestPriDSD; +} + +static int ReadISOSignature(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val iso) +{ + unsigned int uiISOsig = 0; + /* unsigned int sigoffsetInMap = 0; + * struct bcm_iso_header ISOHeader = {0}; + * sigoffsetInMap =(PUCHAR)&(ISOHeader.ISOImageMagicNumber) -(PUCHAR)&ISOHeader; + */ + if (iso != ISO_IMAGE1 && iso != ISO_IMAGE2) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "passed section value is not for ISOs"); + return STATUS_FAILURE; + } + BcmFlash2xBulkRead(Adapter, + &uiISOsig, + iso, + 0 + FIELD_OFFSET_IN_HEADER(struct bcm_iso_header *, ISOImageMagicNumber), + SIGNATURE_SIZE); + + uiISOsig = ntohl(uiISOsig); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISO SIG :%x", uiISOsig); + + return uiISOsig; +} + +static int ReadISOPriority(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val iso) +{ + unsigned int ISOPri = STATUS_FAILURE; + if (IsSectionWritable(Adapter, iso)) { + if (ReadISOSignature(Adapter, iso) == ISO_IMAGE_MAGIC_NUMBER) { + BcmFlash2xBulkRead(Adapter, + &ISOPri, + iso, + 0 + FIELD_OFFSET_IN_HEADER(struct bcm_iso_header *, ISOImagePriority), + 4); + + ISOPri = ntohl(ISOPri); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "ISO<%x> Priority :%x", iso, ISOPri); + } + } + + return ISOPri; +} + +static enum bcm_flash2x_section_val getHighestPriISO(struct bcm_mini_adapter *Adapter) +{ + int ISOHighestPri = STATUS_FAILURE; + int ISOPri = 0; + enum bcm_flash2x_section_val HighestPriISO = NO_SECTION_VAL; + + if (IsSectionWritable(Adapter, ISO_IMAGE2)) { + ISOHighestPri = ReadISOPriority(Adapter, ISO_IMAGE2); + HighestPriISO = ISO_IMAGE2; + } + + if (IsSectionWritable(Adapter, ISO_IMAGE1)) { + ISOPri = ReadISOPriority(Adapter, ISO_IMAGE1); + if (ISOHighestPri < ISOPri) { + ISOHighestPri = ISOPri; + HighestPriISO = ISO_IMAGE1; + } + } + if (HighestPriISO) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Highest ISO :%x and its Pri :%x", HighestPriISO, ISOHighestPri); + + return HighestPriISO; +} + +static int WriteToFlashWithoutSectorErase(struct bcm_mini_adapter *Adapter, + PUINT pBuff, + enum bcm_flash2x_section_val eFlash2xSectionVal, + unsigned int uiOffset, + unsigned int uiNumBytes) +{ + #if !defined(BCM_SHM_INTERFACE) || defined(FLASH_DIRECT_ACCESS) + unsigned int uiTemp = 0, value = 0; + unsigned int i = 0; + unsigned int uiPartOffset = 0; + #endif + unsigned int uiStartOffset = 0; + /* Adding section start address */ + int Status = STATUS_SUCCESS; + PUCHAR pcBuff = (PUCHAR)pBuff; + + if (uiNumBytes % Adapter->ulFlashWriteSize) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Writing without Sector Erase for non-FlashWriteSize number of bytes 0x%x\n", uiNumBytes); + return STATUS_FAILURE; + } + + uiStartOffset = BcmGetSectionValStartOffset(Adapter, eFlash2xSectionVal); + + if (IsSectionExistInVendorInfo(Adapter, eFlash2xSectionVal)) + return vendorextnWriteSectionWithoutErase(Adapter, pcBuff, eFlash2xSectionVal, uiOffset, uiNumBytes); + + uiOffset = uiOffset + uiStartOffset; + + #if defined(BCM_SHM_INTERFACE) && !defined(FLASH_DIRECT_ACCESS) + Status = bcmflash_raw_writenoerase((uiOffset / FLASH_PART_SIZE), (uiOffset % FLASH_PART_SIZE), pcBuff, uiNumBytes); + #else + rdmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp)); + value = 0; + wrmalt(Adapter, 0x0f000C80, &value, sizeof(value)); + + Adapter->SelectedChip = RESET_CHIP_SELECT; + BcmDoChipSelect(Adapter, uiOffset); + uiPartOffset = (uiOffset & (FLASH_PART_SIZE - 1)) + GetFlashBaseAddr(Adapter); + + for (i = 0; i < uiNumBytes; i += Adapter->ulFlashWriteSize) { + if (Adapter->ulFlashWriteSize == BYTE_WRITE_SUPPORT) + Status = flashByteWrite(Adapter, uiPartOffset, pcBuff); + else + Status = flashWrite(Adapter, uiPartOffset, pcBuff); + + if (Status != STATUS_SUCCESS) + break; + + pcBuff = pcBuff + Adapter->ulFlashWriteSize; + uiPartOffset = uiPartOffset + Adapter->ulFlashWriteSize; + } + wrmalt(Adapter, 0x0f000C80, &uiTemp, sizeof(uiTemp)); + Adapter->SelectedChip = RESET_CHIP_SELECT; + #endif + + return Status; +} + +bool IsSectionExistInFlash(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val section) +{ + bool SectionPresent = false; + + switch (section) { + case ISO_IMAGE1: + if ((Adapter->psFlash2xCSInfo->OffsetISOImage1Part1Start != UNINIT_PTR_IN_CS) && + (IsNonCDLessDevice(Adapter) == false)) + SectionPresent = TRUE; + break; + case ISO_IMAGE2: + if ((Adapter->psFlash2xCSInfo->OffsetISOImage2Part1Start != UNINIT_PTR_IN_CS) && + (IsNonCDLessDevice(Adapter) == false)) + SectionPresent = TRUE; + break; + case DSD0: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSDStart != UNINIT_PTR_IN_CS) + SectionPresent = TRUE; + break; + case DSD1: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD1Start != UNINIT_PTR_IN_CS) + SectionPresent = TRUE; + break; + case DSD2: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForDSD2Start != UNINIT_PTR_IN_CS) + SectionPresent = TRUE; + break; + case VSA0: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSAStart != UNINIT_PTR_IN_CS) + SectionPresent = TRUE; + break; + case VSA1: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA1Start != UNINIT_PTR_IN_CS) + SectionPresent = TRUE; + break; + case VSA2: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForVSA2Start != UNINIT_PTR_IN_CS) + SectionPresent = TRUE; + break; + case SCSI: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForScsiFirmware != UNINIT_PTR_IN_CS) + SectionPresent = TRUE; + break; + case CONTROL_SECTION: + if (Adapter->psFlash2xCSInfo->OffsetFromZeroForControlSectionStart != UNINIT_PTR_IN_CS) + SectionPresent = TRUE; + break; + default: + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section Does not exist in Flash 2.x"); + SectionPresent = false; + } + + return SectionPresent; +} + +static int IsSectionWritable(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val Section) +{ + int offset = STATUS_FAILURE; + int Status = false; + + if (IsSectionExistInFlash(Adapter, Section) == false) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section <%d> does not exist", Section); + return false; + } + + offset = BcmGetSectionValStartOffset(Adapter, Section); + if (offset == INVALID_OFFSET) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section<%d> does not exist", Section); + return false; + } + + if (IsSectionExistInVendorInfo(Adapter, Section)) + return !(Adapter->psFlash2xVendorInfo->VendorSection[Section].AccessFlags & FLASH2X_SECTION_RO); + + Status = IsOffsetWritable(Adapter, offset); + return Status; +} + +static int CorruptDSDSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectionVal) +{ + PUCHAR pBuff = NULL; + unsigned int sig = 0; + unsigned int uiOffset = 0; + unsigned int BlockStatus = 0; + unsigned int uiSectAlignAddr = 0; + + Adapter->bSigCorrupted = false; + if (Adapter->bAllDSDWriteAllow == false) { + if (IsSectionWritable(Adapter, eFlash2xSectionVal) != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section is not Writable...Hence can't Corrupt signature"); + return SECTOR_IS_NOT_WRITABLE; + } + } + + pBuff = kzalloc(MAX_RW_SIZE, GFP_KERNEL); + if (!pBuff) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Can't allocate memorey"); + return -ENOMEM; + } + + uiOffset = Adapter->psFlash2xCSInfo->OffsetFromDSDStartForDSDHeader + sizeof(struct bcm_dsd_header); + uiOffset -= MAX_RW_SIZE; + + BcmFlash2xBulkRead(Adapter, (PUINT)pBuff, eFlash2xSectionVal, uiOffset, MAX_RW_SIZE); + + sig = *((PUINT)(pBuff + 12)); + sig = ntohl(sig); + BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, pBuff, MAX_RW_SIZE); + /* Now corrupting the sig by corrupting 4th last Byte. */ + *(pBuff + 12) = 0; + + if (sig == DSD_IMAGE_MAGIC_NUMBER) { + Adapter->bSigCorrupted = TRUE; + if (Adapter->ulFlashWriteSize == BYTE_WRITE_SUPPORT) { + uiSectAlignAddr = uiOffset & ~(Adapter->uiSectorSize - 1); + BlockStatus = BcmFlashUnProtectBlock(Adapter, uiSectAlignAddr, Adapter->uiSectorSize); + + WriteToFlashWithoutSectorErase(Adapter, (PUINT)(pBuff + 12), eFlash2xSectionVal, + (uiOffset + 12), BYTE_WRITE_SUPPORT); + if (BlockStatus) { + BcmRestoreBlockProtectStatus(Adapter, BlockStatus); + BlockStatus = 0; + } + } else { + WriteToFlashWithoutSectorErase(Adapter, (PUINT)pBuff, eFlash2xSectionVal, + uiOffset, MAX_RW_SIZE); + } + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "BCM Signature is not present in header"); + kfree(pBuff); + + return STATUS_FAILURE; + } + + kfree(pBuff); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Corrupted the signature"); + + return STATUS_SUCCESS; +} + +static int CorruptISOSig(struct bcm_mini_adapter *Adapter, enum bcm_flash2x_section_val eFlash2xSectionVal) +{ + PUCHAR pBuff = NULL; + unsigned int sig = 0; + unsigned int uiOffset = 0; + + Adapter->bSigCorrupted = false; + + if (IsSectionWritable(Adapter, eFlash2xSectionVal) != TRUE) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Section is not Writable...Hence can't Corrupt signature"); + return SECTOR_IS_NOT_WRITABLE; + } + + pBuff = kzalloc(MAX_RW_SIZE, GFP_KERNEL); + if (!pBuff) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Can't allocate memorey"); + return -ENOMEM; + } + + uiOffset = 0; + + BcmFlash2xBulkRead(Adapter, (PUINT)pBuff, eFlash2xSectionVal, uiOffset, MAX_RW_SIZE); + + sig = *((PUINT)pBuff); + sig = ntohl(sig); + + /* corrupt signature */ + *pBuff = 0; + + if (sig == ISO_IMAGE_MAGIC_NUMBER) { + Adapter->bSigCorrupted = TRUE; + WriteToFlashWithoutSectorErase(Adapter, (PUINT)pBuff, eFlash2xSectionVal, + uiOffset, Adapter->ulFlashWriteSize); + } else { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "BCM Signature is not present in header"); + kfree(pBuff); + + return STATUS_FAILURE; + } + + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, "Corrupted the signature"); + BCM_DEBUG_PRINT_BUFFER(Adapter, DBG_TYPE_OTHERS, NVM_RW, DBG_LVL_ALL, pBuff, MAX_RW_SIZE); + + kfree(pBuff); + return STATUS_SUCCESS; +} + +bool IsNonCDLessDevice(struct bcm_mini_adapter *Adapter) +{ + if (Adapter->psFlash2xCSInfo->IsCDLessDeviceBootSig == NON_CDLESS_DEVICE_BOOT_SIG) + return TRUE; + else + return false; +} diff --git a/drivers/staging/bcm/nvm.h b/drivers/staging/bcm/nvm.h new file mode 100644 index 00000000000..e765cca5d96 --- /dev/null +++ b/drivers/staging/bcm/nvm.h @@ -0,0 +1,286 @@ +/*************************************************************************************** + * + * Copyright (c) Beceem Communications Inc. + * + * Module Name: + * NVM.h + * + * Abstract: + * This file has the prototypes,preprocessors and definitions various NVM libraries. + * + * + * Revision History: + * Who When What + * -------- -------- ---------------------------------------------- + * Name Date Created/reviewed/modified + * + * Notes: + * + ****************************************************************************************/ + +#ifndef _NVM_H_ +#define _NVM_H_ + +struct bcm_flash_cs_info { + u32 MagicNumber; + /* let the magic number be 0xBECE-F1A5 - F1A5 for "flas-h" */ + u32 FlashLayoutVersion; + u32 ISOImageVersion; + u32 SCSIFirmwareVersion; + u32 OffsetFromZeroForPart1ISOImage; + u32 OffsetFromZeroForScsiFirmware; + u32 SizeOfScsiFirmware; + u32 OffsetFromZeroForPart2ISOImage; + u32 OffsetFromZeroForCalibrationStart; + u32 OffsetFromZeroForCalibrationEnd; + u32 OffsetFromZeroForVSAStart; + u32 OffsetFromZeroForVSAEnd; + u32 OffsetFromZeroForControlSectionStart; + u32 OffsetFromZeroForControlSectionData; + u32 CDLessInactivityTimeout; + u32 NewImageSignature; + u32 FlashSectorSizeSig; + u32 FlashSectorSize; + u32 FlashWriteSupportSize; + u32 TotalFlashSize; + u32 FlashBaseAddr; + u32 FlashPartMaxSize; + u32 IsCDLessDeviceBootSig; + /* MSC Timeout after reset to switch from MSC to NW Mode */ + u32 MassStorageTimeout; +}; + +#define FLASH2X_TOTAL_SIZE (64 * 1024 * 1024) +#define DEFAULT_SECTOR_SIZE (64 * 1024) + +struct bcm_flash2x_cs_info { + /* magic number as 0xBECE-F1A5 - F1A5 for "flas-h" */ + u32 MagicNumber; + u32 FlashLayoutVersion; + u32 ISOImageVersion; + u32 SCSIFirmwareVersion; + u32 OffsetFromZeroForPart1ISOImage; + u32 OffsetFromZeroForScsiFirmware; + u32 SizeOfScsiFirmware; + u32 OffsetFromZeroForPart2ISOImage; + u32 OffsetFromZeroForDSDStart; + u32 OffsetFromZeroForDSDEnd; + u32 OffsetFromZeroForVSAStart; + u32 OffsetFromZeroForVSAEnd; + u32 OffsetFromZeroForControlSectionStart; + u32 OffsetFromZeroForControlSectionData; + /* NO Data Activity timeout to switch from MSC to NW Mode */ + u32 CDLessInactivityTimeout; + u32 NewImageSignature; + u32 FlashSectorSizeSig; + u32 FlashSectorSize; + u32 FlashWriteSupportSize; + u32 TotalFlashSize; + u32 FlashBaseAddr; + u32 FlashPartMaxSize; + u32 IsCDLessDeviceBootSig; + /* MSC Timeout after reset to switch from MSC to NW Mode */ + u32 MassStorageTimeout; + /* Flash Map 2.0 Field */ + u32 OffsetISOImage1Part1Start; + u32 OffsetISOImage1Part1End; + u32 OffsetISOImage1Part2Start; + u32 OffsetISOImage1Part2End; + u32 OffsetISOImage1Part3Start; + u32 OffsetISOImage1Part3End; + u32 OffsetISOImage2Part1Start; + u32 OffsetISOImage2Part1End; + u32 OffsetISOImage2Part2Start; + u32 OffsetISOImage2Part2End; + u32 OffsetISOImage2Part3Start; + u32 OffsetISOImage2Part3End; + /* DSD Header offset from start of DSD */ + u32 OffsetFromDSDStartForDSDHeader; + u32 OffsetFromZeroForDSD1Start; + u32 OffsetFromZeroForDSD1End; + u32 OffsetFromZeroForDSD2Start; + u32 OffsetFromZeroForDSD2End; + u32 OffsetFromZeroForVSA1Start; + u32 OffsetFromZeroForVSA1End; + u32 OffsetFromZeroForVSA2Start; + u32 OffsetFromZeroForVSA2End; + /* + * ACCESS_BITS_PER_SECTOR 2 + * ACCESS_RW 0 + * ACCESS_RO 1 + * ACCESS_RESVD 2 + * ACCESS_RESVD 3 + */ + u32 SectorAccessBitMap[FLASH2X_TOTAL_SIZE / (DEFAULT_SECTOR_SIZE * 16)]; + /* All expansions to the control data structure should add here */ +}; + +struct bcm_vendor_section_info { + u32 OffsetFromZeroForSectionStart; + u32 OffsetFromZeroForSectionEnd; + u32 AccessFlags; + u32 Reserved[16]; +}; + +struct bcm_flash2x_vendor_info { + struct bcm_vendor_section_info VendorSection[TOTAL_SECTIONS]; + u32 Reserved[16]; +}; + +struct bcm_dsd_header { + u32 DSDImageSize; + u32 DSDImageCRC; + u32 DSDImagePriority; + /* We should not consider right now. Reading reserve is worthless. */ + u32 Reserved[252]; /* Resvd for DSD Header */ + u32 DSDImageMagicNumber; +}; + +struct bcm_iso_header { + u32 ISOImageMagicNumber; + u32 ISOImageSize; + u32 ISOImageCRC; + u32 ISOImagePriority; + /* We should not consider right now. Reading reserve is worthless. */ + u32 Reserved[60]; /* Resvd for ISO Header extension */ +}; + +#define EEPROM_BEGIN_CIS (0) +#define EEPROM_BEGIN_NON_CIS (0x200) +#define EEPROM_END (0x2000) +#define INIT_PARAMS_SIGNATURE (0x95a7a597) +#define MAX_INIT_PARAMS_LENGTH (2048) +#define MAC_ADDRESS_OFFSET 0x200 + +#define INIT_PARAMS_1_SIGNATURE_ADDRESS EEPROM_BEGIN_NON_CIS +#define INIT_PARAMS_1_DATA_ADDRESS (INIT_PARAMS_1_SIGNATURE_ADDRESS+16) +#define INIT_PARAMS_1_MACADDRESS_ADDRESS (MAC_ADDRESS_OFFSET) +#define INIT_PARAMS_1_LENGTH_ADDRESS (INIT_PARAMS_1_SIGNATURE_ADDRESS+4) + +#define INIT_PARAMS_2_SIGNATURE_ADDRESS (EEPROM_BEGIN_NON_CIS + 2048 + 16) +#define INIT_PARAMS_2_DATA_ADDRESS (INIT_PARAMS_2_SIGNATURE_ADDRESS + 16) +#define INIT_PARAMS_2_MACADDRESS_ADDRESS (INIT_PARAMS_2_SIGNATURE_ADDRESS + 8) +#define INIT_PARAMS_2_LENGTH_ADDRESS (INIT_PARAMS_2_SIGNATURE_ADDRESS + 4) + +#define EEPROM_SPI_DEV_CONFIG_REG 0x0F003000 +#define EEPROM_SPI_Q_STATUS1_REG 0x0F003004 +#define EEPROM_SPI_Q_STATUS1_MASK_REG 0x0F00300C + +#define EEPROM_SPI_Q_STATUS_REG 0x0F003008 +#define EEPROM_CMDQ_SPI_REG 0x0F003018 +#define EEPROM_WRITE_DATAQ_REG 0x0F00301C +#define EEPROM_READ_DATAQ_REG 0x0F003020 +#define SPI_FLUSH_REG 0x0F00304C + +#define EEPROM_WRITE_ENABLE 0x06000000 +#define EEPROM_READ_STATUS_REGISTER 0x05000000 +#define EEPROM_16_BYTE_PAGE_WRITE 0xFA000000 +#define EEPROM_WRITE_QUEUE_EMPTY 0x00001000 +#define EEPROM_WRITE_QUEUE_AVAIL 0x00002000 +#define EEPROM_WRITE_QUEUE_FULL 0x00004000 +#define EEPROM_16_BYTE_PAGE_READ 0xFB000000 +#define EEPROM_4_BYTE_PAGE_READ 0x3B000000 + +#define EEPROM_CMD_QUEUE_FLUSH 0x00000001 +#define EEPROM_WRITE_QUEUE_FLUSH 0x00000002 +#define EEPROM_READ_QUEUE_FLUSH 0x00000004 +#define EEPROM_ETH_QUEUE_FLUSH 0x00000008 +#define EEPROM_ALL_QUEUE_FLUSH 0x0000000f +#define EEPROM_READ_ENABLE 0x06000000 +#define EEPROM_16_BYTE_PAGE_WRITE 0xFA000000 +#define EEPROM_READ_DATA_FULL 0x00000010 +#define EEPROM_READ_DATA_AVAIL 0x00000020 +#define EEPROM_READ_QUEUE_EMPTY 0x00000002 +#define EEPROM_CMD_QUEUE_EMPTY 0x00000100 +#define EEPROM_CMD_QUEUE_AVAIL 0x00000200 +#define EEPROM_CMD_QUEUE_FULL 0x00000400 + +/* Most EEPROM status register bit 0 indicates if the EEPROM is busy + * with a write if set 1. See the details of the EEPROM Status Register + * in the EEPROM data sheet. + */ +#define EEPROM_STATUS_REG_WRITE_BUSY 0x00000001 + +/* We will have 1 mSec for every RETRIES_PER_DELAY count and have a max attempts of MAX_EEPROM_RETRIES + * This will give us 80 mSec minimum of delay = 80mSecs + */ +#define MAX_EEPROM_RETRIES 80 +#define RETRIES_PER_DELAY 64 +#define MAX_RW_SIZE 0x10 +#define MAX_READ_SIZE 0x10 +#define MAX_SECTOR_SIZE (512 * 1024) +#define MIN_SECTOR_SIZE (1024) +#define FLASH_SECTOR_SIZE_OFFSET 0xEFFFC +#define FLASH_SECTOR_SIZE_SIG_OFFSET 0xEFFF8 +#define FLASH_SECTOR_SIZE_SIG 0xCAFEBABE +#define FLASH_CS_INFO_START_ADDR 0xFF0000 +#define FLASH_CONTROL_STRUCT_SIGNATURE 0xBECEF1A5 +#define SCSI_FIRMWARE_MAJOR_VERSION 0x1 +#define SCSI_FIRMWARE_MINOR_VERSION 0x5 +#define BYTE_WRITE_SUPPORT 0x1 +#define FLASH_AUTO_INIT_BASE_ADDR 0xF00000 +#define FLASH_CONTIGIOUS_START_ADDR_AFTER_INIT 0x1C000000 +#define FLASH_CONTIGIOUS_START_ADDR_BEFORE_INIT 0x1F000000 +#define FLASH_CONTIGIOUS_START_ADDR_BCS350 0x08000000 +#define FLASH_CONTIGIOUS_END_ADDR_BCS350 0x08FFFFFF +#define FLASH_SIZE_ADDR 0xFFFFEC +#define FLASH_SPI_CMDQ_REG 0xAF003040 +#define FLASH_SPI_WRITEQ_REG 0xAF003044 +#define FLASH_SPI_READQ_REG 0xAF003048 +#define FLASH_CONFIG_REG 0xAF003050 +#define FLASH_GPIO_CONFIG_REG 0xAF000030 +#define FLASH_CMD_WRITE_ENABLE 0x06 +#define FLASH_CMD_READ_ENABLE 0x03 +#define FLASH_CMD_RESET_WRITE_ENABLE 0x04 +#define FLASH_CMD_STATUS_REG_READ 0x05 +#define FLASH_CMD_STATUS_REG_WRITE 0x01 +#define FLASH_CMD_READ_ID 0x9F +#define PAD_SELECT_REGISTER 0xAF000410 +#define FLASH_PART_SST25VF080B 0xBF258E +#define EEPROM_CAL_DATA_INTERNAL_LOC 0xbFB00008 +#define EEPROM_CALPARAM_START 0x200 +#define EEPROM_SIZE_OFFSET 524 + +/* As Read/Write time vaires from 1.5 to 3.0 ms. + * so After Ignoring the rdm/wrm time(that is dependent on many factor like interface etc.), + * here time calculated meets the worst case delay, 3.0 ms + */ +#define MAX_FLASH_RETRIES 4 +#define FLASH_PER_RETRIES_DELAY 16 +#define EEPROM_MAX_CAL_AREA_SIZE 0xF0000 +#define BECM ntohl(0x4245434d) +#define FLASH_2X_MAJOR_NUMBER 0x2 +#define DSD_IMAGE_MAGIC_NUMBER 0xBECE0D5D +#define ISO_IMAGE_MAGIC_NUMBER 0xBECE0150 +#define NON_CDLESS_DEVICE_BOOT_SIG 0xBECEB007 + +#define MINOR_VERSION(x) ((x >> 16) & 0xFFFF) +#define MAJOR_VERSION(x) (x & 0xFFFF) + +#define CORRUPTED_PATTERN 0x0 +#define UNINIT_PTR_IN_CS 0xBBBBDDDD +#define VENDOR_PTR_IN_CS 0xAAAACCCC +#define FLASH2X_SECTION_PRESENT (1 << 0) +#define FLASH2X_SECTION_VALID (1 << 1) +#define FLASH2X_SECTION_RO (1 << 2) +#define FLASH2X_SECTION_ACT (1 << 3) +#define SECTOR_IS_NOT_WRITABLE STATUS_FAILURE +#define INVALID_OFFSET STATUS_FAILURE +#define INVALID_SECTION STATUS_FAILURE +#define SECTOR_1K 1024 +#define SECTOR_64K (64 * SECTOR_1K) +#define SECTOR_128K (2 * SECTOR_64K) +#define SECTOR_256k (2 * SECTOR_128K) +#define SECTOR_512K (2 * SECTOR_256k) +#define FLASH_PART_SIZE (16 * 1024 * 1024) +#define RESET_CHIP_SELECT -1 +#define CHIP_SELECT_BIT12 12 +#define SECTOR_READWRITE_PERMISSION 0 +#define SECTOR_READONLY 1 +#define SIGNATURE_SIZE 4 +#define DEFAULT_BUFF_SIZE 0x10000 + +#define FIELD_OFFSET_IN_HEADER(HeaderPointer, Field) ((u8 *)&((HeaderPointer)(NULL))->Field - (u8 *)(NULL)) + +#endif + diff --git a/drivers/staging/bcm/sort.c b/drivers/staging/bcm/sort.c new file mode 100644 index 00000000000..d518c4217f1 --- /dev/null +++ b/drivers/staging/bcm/sort.c @@ -0,0 +1,52 @@ +#include "headers.h" +#include <linux/sort.h> + +/* + * File Name: sort.c + * + * Author: Beceem Communications Pvt. Ltd + * + * Abstract: This file contains the routines sorting the classification rules. + * + * Copyright (c) 2007 Beceem Communications Pvt. Ltd + */ + +static int compare_packet_info(void const *a, void const *b) +{ + struct bcm_packet_info const *pa = a; + struct bcm_packet_info const *pb = b; + + if (!pa->bValid || !pb->bValid) + return 0; + + return pa->u8TrafficPriority - pb->u8TrafficPriority; +} + +VOID SortPackInfo(struct bcm_mini_adapter *Adapter) +{ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, + DBG_LVL_ALL, "<======="); + + sort(Adapter->PackInfo, NO_OF_QUEUES, sizeof(struct bcm_packet_info), + compare_packet_info, NULL); +} + +static int compare_classifiers(void const *a, void const *b) +{ + struct bcm_classifier_rule const *pa = a; + struct bcm_classifier_rule const *pb = b; + + if (!pa->bUsed || !pb->bUsed) + return 0; + + return pa->u8ClassifierRulePriority - pb->u8ClassifierRulePriority; +} + +VOID SortClassifiers(struct bcm_mini_adapter *Adapter) +{ + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, + DBG_LVL_ALL, "<======="); + + sort(Adapter->astClassifierTable, MAX_CLASSIFIERS, + sizeof(struct bcm_classifier_rule), compare_classifiers, NULL); +} diff --git a/drivers/staging/bcm/target_params.h b/drivers/staging/bcm/target_params.h new file mode 100644 index 00000000000..dc45f9ab854 --- /dev/null +++ b/drivers/staging/bcm/target_params.h @@ -0,0 +1,57 @@ +#ifndef TARGET_PARAMS_H +#define TARGET_PARAMS_H + +struct bcm_target_params { + u32 m_u32CfgVersion; + u32 m_u32CenterFrequency; + u32 m_u32BandAScan; + u32 m_u32BandBScan; + u32 m_u32BandCScan; + u32 m_u32ErtpsOptions; + u32 m_u32PHSEnable; + u32 m_u32HoEnable; + u32 m_u32HoReserved1; + u32 m_u32HoReserved2; + u32 m_u32MimoEnable; + u32 m_u32SecurityEnable; + u32 m_u32PowerSavingModesEnable; /* bit 1: 1 Idlemode enable; bit2: 1 Sleepmode Enable */ + /* PowerSaving Mode Options: + * bit 0 = 1: CPE mode - to keep pcmcia if alive; + * bit 1 = 1: CINR reporting in Idlemode Msg + * bit 2 = 1: Default PSC Enable in sleepmode + */ + u32 m_u32PowerSavingModeOptions; + u32 m_u32ArqEnable; + /* From Version #3, the HARQ section renamed as general */ + u32 m_u32HarqEnable; + u32 m_u32EEPROMFlag; + /* BINARY TYPE - 4th MSByte: Interface Type - 3rd MSByte: Vendor Type - 2nd MSByte + * Unused - LSByte + */ + u32 m_u32Customize; + u32 m_u32ConfigBW; /* In Hz */ + u32 m_u32ShutDownInitThresholdTimer; + u32 m_u32RadioParameter; + u32 m_u32PhyParameter1; + u32 m_u32PhyParameter2; + u32 m_u32PhyParameter3; + u32 m_u32TestOptions; /* in eval mode only; lower 16bits = basic cid for testing; then bit 16 is test cqich,bit 17 test init rang; bit 18 test periodic rang and bit 19 is test harq ack/nack */ + u32 m_u32MaxMACDataperDLFrame; + u32 m_u32MaxMACDataperULFrame; + u32 m_u32Corr2MacFlags; + u32 HostDrvrConfig1; + u32 HostDrvrConfig2; + u32 HostDrvrConfig3; + u32 HostDrvrConfig4; + u32 HostDrvrConfig5; + u32 HostDrvrConfig6; + u32 m_u32SegmentedPUSCenable; + /* removed SHUT down related 'unused' params from here to sync 4.x and 5.x CFG files.. + * BAMC Related Parameters + * Bit 0-15 Band AMC signaling configuration: Bit 1 = 1 Enable Band AMC signaling. + * bit 16-31 Band AMC Data configuration: Bit 16 = 1 Band AMC 2x3 support. + */ + u32 m_u32BandAMCEnable; +}; + +#endif diff --git a/drivers/staging/bcm/vendorspecificextn.c b/drivers/staging/bcm/vendorspecificextn.c new file mode 100644 index 00000000000..2c57a16788c --- /dev/null +++ b/drivers/staging/bcm/vendorspecificextn.c @@ -0,0 +1,142 @@ +#include "headers.h" +/* + * Procedure: vendorextnGetSectionInfo + * + * Description: Finds the type of NVM used. + * + * Arguments: + * Adapter - ptr to Adapter object instance + * pNVMType - ptr to NVM type. + * Returns: + * STATUS_SUCCESS/STATUS_FAILURE + * + */ +INT vendorextnGetSectionInfo(PVOID pContext, struct bcm_flash2x_vendor_info *pVendorInfo) +{ + return STATUS_FAILURE; +} + +/* + * Procedure: vendorextnInit + * + * Description: Initializing the vendor extension NVM interface + * + * Arguments: + * Adapter - Pointer to MINI Adapter Structure + * Returns: + * STATUS_SUCCESS/STATUS_FAILURE + * + * + */ +INT vendorextnInit(struct bcm_mini_adapter *Adapter) +{ + return STATUS_SUCCESS; +} + +/* + * Procedure: vendorextnExit + * + * Description: Free the resource associated with vendor extension NVM interface + * + * Arguments: + * + * Returns: + * STATUS_SUCCESS/STATUS_FAILURE + * + * + */ +INT vendorextnExit(struct bcm_mini_adapter *Adapter) +{ + return STATUS_SUCCESS; +} + +/* + * Procedure: vendorextnIoctl + * + * Description: execute the vendor extension specific ioctl + * + * Arguments: + * Adapter -Beceem private Adapter Structure + * cmd -vendor extension specific Ioctl commad + * arg -input parameter sent by vendor + * + * Returns: + * CONTINUE_COMMON_PATH in case it is not meant to be processed by vendor ioctls + * STATUS_SUCCESS/STATUS_FAILURE as per the IOCTL return value + */ + +INT vendorextnIoctl(struct bcm_mini_adapter *Adapter, UINT cmd, ULONG arg) +{ + return CONTINUE_COMMON_PATH; +} + + + +/* + * Procedure: vendorextnReadSection + * + * Description: Reads from a section of NVM + * + * Arguments: + * pContext - ptr to Adapter object instance + * pBuffer - Read the data from Vendor Area to this buffer + * SectionVal - Value of type of Section + * Offset - Read from the Offset of the Vendor Section. + * numOfBytes - Read numOfBytes from the Vendor section to Buffer + * + * Returns: + * STATUS_SUCCESS/STATUS_FAILURE + */ + +INT vendorextnReadSection(PVOID pContext, PUCHAR pBuffer, enum bcm_flash2x_section_val SectionVal, + UINT offset, UINT numOfBytes) +{ + return STATUS_FAILURE; +} + + + +/* + * Procedure: vendorextnWriteSection + * + * Description: Write to a Section of NVM + * + * Arguments: + * pContext - ptr to Adapter object instance + * pBuffer - Write the data provided in the buffer + * SectionVal - Value of type of Section + * Offset - Writes to the Offset of the Vendor Section. + * numOfBytes - Write num Bytes after reading from pBuffer. + * bVerify - the Buffer Written should be verified. + * + * Returns: + * STATUS_SUCCESS/STATUS_FAILURE + */ +INT vendorextnWriteSection(PVOID pContext, PUCHAR pBuffer, enum bcm_flash2x_section_val SectionVal, + UINT offset, UINT numOfBytes, bool bVerify) +{ + return STATUS_FAILURE; +} + + + +/* + * Procedure: vendorextnWriteSectionWithoutErase + * + * Description: Write to a Section of NVM without erasing the sector + * + * Arguments: + * pContext - ptr to Adapter object instance + * pBuffer - Write the data provided in the buffer + * SectionVal - Value of type of Section + * Offset - Writes to the Offset of the Vendor Section. + * numOfBytes - Write num Bytes after reading from pBuffer. + * + * Returns: + * STATUS_SUCCESS/STATUS_FAILURE + */ +INT vendorextnWriteSectionWithoutErase(PVOID pContext, PUCHAR pBuffer, enum bcm_flash2x_section_val SectionVal, + UINT offset, UINT numOfBytes) +{ + return STATUS_FAILURE; +} diff --git a/drivers/staging/bcm/vendorspecificextn.h b/drivers/staging/bcm/vendorspecificextn.h new file mode 100644 index 00000000000..ff57f057045 --- /dev/null +++ b/drivers/staging/bcm/vendorspecificextn.h @@ -0,0 +1,18 @@ + +#ifndef __VENDOR_EXTN_NVM_H__ +#define __VENDOR_EXTN_NVM_H__ + +#define CONTINUE_COMMON_PATH 0xFFFF + +INT vendorextnGetSectionInfo(PVOID pContext, struct bcm_flash2x_vendor_info *pVendorInfo); +INT vendorextnExit(struct bcm_mini_adapter *Adapter); +INT vendorextnInit(struct bcm_mini_adapter *Adapter); +INT vendorextnIoctl(struct bcm_mini_adapter *Adapter, UINT cmd, ULONG arg); +INT vendorextnReadSection(PVOID pContext, PUCHAR pBuffer, enum bcm_flash2x_section_val SectionVal, + UINT offset, UINT numOfBytes); +INT vendorextnWriteSection(PVOID pContext, PUCHAR pBuffer, enum bcm_flash2x_section_val SectionVal, + UINT offset, UINT numOfBytes, bool bVerify); +INT vendorextnWriteSectionWithoutErase(PVOID pContext, PUCHAR pBuffer, enum bcm_flash2x_section_val SectionVal, + UINT offset, UINT numOfBytes); + +#endif /* */ |
