diff options
Diffstat (limited to 'drivers/net/wireless/bcmdhd/src/dhd')
17 files changed, 0 insertions, 22465 deletions
diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd.h b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd.h deleted file mode 100644 index 44fd410..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd.h +++ /dev/null @@ -1,864 +0,0 @@ -/* - * Header file describing the internal (inter-module) DHD interfaces. - * - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2012, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd.h 309548 2012-01-20 01:13:08Z $ - */ - -/**************** - * Common types * - */ - -#ifndef _dhd_h_ -#define _dhd_h_ - -#include "dhd_sec_feature.h" -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/random.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <asm/uaccess.h> -#include <asm/unaligned.h> -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) -#include <linux/wakelock.h> -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ -/* The kernel threading is sdio-specific */ -struct task_struct; -struct sched_param; -int setScheduler(struct task_struct *p, int policy, struct sched_param *param); - -#define ALL_INTERFACES 0xff - -#include <wlioctl.h> -#include <wlfc_proto.h> - -// For dual support of WCN3660 and BCM4334 -#undef CONFIG_WIRELESS_EXT - -/* Forward decls */ -struct dhd_bus; -struct dhd_prot; -struct dhd_info; - -/* The level of bus communication with the dongle */ -enum dhd_bus_state { - DHD_BUS_DOWN, /* Not ready for frame transfers */ - DHD_BUS_LOAD, /* Download access only (CPU reset) */ - DHD_BUS_DATA /* Ready for frame transfers */ -}; - - -/* Firmware requested operation mode */ -#define STA_MASK 0x0001 -#define HOSTAPD_MASK 0x0002 -#define WFD_MASK 0x0004 -#define SOFTAP_FW_MASK 0x0008 -#define CONCURRENT_MASK (STA_MASK | WFD_MASK) - -/* max sequential rxcntl timeouts to set HANG event */ -#ifdef BCM4334_CHIP -#define MAX_CNTL_TIMEOUT 1 -#else -#define MAX_CNTL_TIMEOUT 2 -#endif - -#define DHD_SCAN_ACTIVE_TIME 40 /* ms : Embedded default Active setting from DHD Driver */ -#define DHD_SCAN_PASSIVE_TIME 130 /* ms: Embedded default Passive setting from DHD Driver */ - -#ifndef POWERUP_MAX_RETRY -#define POWERUP_MAX_RETRY (10) /* how many times we retry to power up the chip */ -#endif -#ifndef POWERUP_WAIT_MS -#define POWERUP_WAIT_MS (2000) /* ms: time out in waiting wifi to come up */ -#endif - -enum dhd_bus_wake_state { - WAKE_LOCK_OFF, - WAKE_LOCK_PRIV, - WAKE_LOCK_DPC, - WAKE_LOCK_IOCTL, - WAKE_LOCK_DOWNLOAD, - WAKE_LOCK_TMOUT, - WAKE_LOCK_WATCHDOG, - WAKE_LOCK_LINK_DOWN_TMOUT, - WAKE_LOCK_PNO_FIND_TMOUT, - WAKE_LOCK_SOFTAP_SET, - WAKE_LOCK_SOFTAP_STOP, - WAKE_LOCK_SOFTAP_START, - WAKE_LOCK_SOFTAP_THREAD, - WAKE_LOCK_MAX -}; - -enum dhd_prealloc_index { - DHD_PREALLOC_PROT = 0, - DHD_PREALLOC_RXBUF, - DHD_PREALLOC_DATABUF, -#if defined (CUSTOMER_HW_SAMSUNG) && defined (CONFIG_DHD_USE_STATIC_BUF) - DHD_PREALLOC_OSL_BUF, - DHD_PREALLOC_WIPHY_ESCAN0 = 5, - DHD_PREALLOC_WIPHY_ESCAN1 -#else - DHD_PREALLOC_OSL_BUF -#endif -}; - -typedef enum { - DHD_IF_NONE = 0, - DHD_IF_ADD, - DHD_IF_DEL, - DHD_IF_CHANGE, - DHD_IF_DELETING -} dhd_if_state_t; - - -#if defined(CONFIG_DHD_USE_STATIC_BUF) - -uint8* dhd_os_prealloc(void *osh, int section, uint size); -void dhd_os_prefree(void *osh, void *addr, uint size); -#define DHD_OS_PREALLOC(osh, section, size) dhd_os_prealloc(osh, section, size) -#define DHD_OS_PREFREE(osh, addr, size) dhd_os_prefree(osh, addr, size) - -#else - -#define DHD_OS_PREALLOC(osh, section, size) MALLOC(osh, size) -#define DHD_OS_PREFREE(osh, addr, size) MFREE(osh, addr, size) - -#endif /* defined(CONFIG_DHD_USE_STATIC_BUF) */ - -/* Packet alignment for most efficient SDIO (can change based on platform) */ -#ifndef DHD_SDALIGN -#define DHD_SDALIGN 32 -#endif - -/* host reordering packts logic */ -/* followed the structure to hold the reorder buffers (void **p) */ -typedef struct reorder_info { - void **p; - uint8 flow_id; - uint8 cur_idx; - uint8 exp_idx; - uint8 max_idx; - uint8 pend_pkts; -} reorder_info_t; - -/* Common structure for module and instance linkage */ -typedef struct dhd_pub { - /* Linkage ponters */ - osl_t *osh; /* OSL handle */ - struct dhd_bus *bus; /* Bus module handle */ - struct dhd_prot *prot; /* Protocol module handle */ - struct dhd_info *info; /* Info module handle */ - - /* Internal dhd items */ - bool up; /* Driver up/down (to OS) */ - bool txoff; /* Transmit flow-controlled */ - bool dongle_reset; /* TRUE = DEVRESET put dongle into reset */ - enum dhd_bus_state busstate; - uint hdrlen; /* Total DHD header length (proto + bus) */ - uint maxctl; /* Max size rxctl request from proto to bus */ - uint rxsz; /* Rx buffer size bus module should use */ - uint8 wme_dp; /* wme discard priority */ - - /* Dongle media info */ - bool iswl; /* Dongle-resident driver is wl */ - ulong drv_version; /* Version of dongle-resident driver */ - struct ether_addr mac; /* MAC address obtained from dongle */ - dngl_stats_t dstats; /* Stats for dongle-based data */ - - /* Additional stats for the bus level */ - ulong tx_packets; /* Data packets sent to dongle */ - ulong tx_multicast; /* Multicast data packets sent to dongle */ - ulong tx_errors; /* Errors in sending data to dongle */ - ulong tx_ctlpkts; /* Control packets sent to dongle */ - ulong tx_ctlerrs; /* Errors sending control frames to dongle */ - ulong rx_packets; /* Packets sent up the network interface */ - ulong rx_multicast; /* Multicast packets sent up the network interface */ - ulong rx_errors; /* Errors processing rx data packets */ - ulong rx_ctlpkts; /* Control frames processed from dongle */ - ulong rx_ctlerrs; /* Errors in processing rx control frames */ - ulong rx_dropped; /* Packets dropped locally (no memory) */ - ulong rx_flushed; /* Packets flushed due to unscheduled sendup thread */ - ulong wd_dpc_sched; /* Number of times dhd dpc scheduled by watchdog timer */ - - ulong rx_readahead_cnt; /* Number of packets where header read-ahead was used. */ - ulong tx_realloc; /* Number of tx packets we had to realloc for headroom */ - ulong fc_packets; /* Number of flow control pkts recvd */ - - /* Last error return */ - int bcmerror; - uint tickcnt; - - /* Last error from dongle */ - int dongle_error; - - uint8 country_code[WLC_CNTRY_BUF_SZ]; - - /* Suspend disable flag and "in suspend" flag */ - int suspend_disable_flag; /* "1" to disable all extra powersaving during suspend */ - int in_suspend; /* flag set to 1 when early suspend called */ -#ifdef PNO_SUPPORT - int pno_enable; /* pno status : "1" is pno enable */ - int pno_suspend; /* pno suspend status : "1" is pno suspended */ -#endif /* PNO_SUPPORT */ - int dtim_skip; /* dtim skip , default 0 means wake each dtim */ - -#ifdef PKT_FILTER_SUPPORT - int early_suspended; /* Early suspend status */ - int dhcp_in_progress; /* DHCP period */ -#endif - - /* Pkt filter defination */ - char * pktfilter[100]; - int pktfilter_count; - - wl_country_t dhd_cspec; /* Current Locale info */ - char eventmask[WL_EVENTING_MASK_LEN]; - int op_mode; /* STA, HostAPD, WFD, SoftAP */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_HAS_WAKELOCK) - struct wake_lock wakelock[WAKE_LOCK_MAX]; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined (CONFIG_HAS_WAKELOCK) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - struct mutex wl_start_stop_lock; /* lock/unlock for Android start/stop */ - struct mutex wl_softap_lock; /* lock/unlock for any SoftAP/STA settings */ -#endif - -#ifdef WLBTAMP - uint16 maxdatablks; -#endif /* WLBTAMP */ -#ifdef PROP_TXSTATUS - int wlfc_enabled; - void* wlfc_state; -#endif - bool roam_env_detection; - bool dongle_isolation; - bool dongle_trap_occured; - int hang_was_sent; - int rxcnt_timeout; /* counter rxcnt timeout to send HANG */ - int txcnt_timeout; /* counter txcnt timeout to send HANG */ -#ifdef WLMEDIA_HTSF - uint8 htsfdlystat_sz; /* Size of delay stats, max 255B */ -#endif - struct reorder_info *reorder_bufs[WLHOST_REORDERDATA_MAXFLOWS]; -#if defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK) - struct wake_lock pno_wakelock; -#endif -} dhd_pub_t; - - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) - - #define DHD_PM_RESUME_WAIT_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); - #define _DHD_PM_RESUME_WAIT(a, b) do {\ - int retry = 0; \ - SMP_RD_BARRIER_DEPENDS(); \ - while (dhd_mmc_suspend && retry++ != b) { \ - SMP_RD_BARRIER_DEPENDS(); \ - wait_event_interruptible_timeout(a, !dhd_mmc_suspend, HZ/100); \ - } \ - } while (0) -#ifdef CUSTOMER_HW_SAMSUNG - #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 500) -#else - #define DHD_PM_RESUME_WAIT(a) _DHD_PM_RESUME_WAIT(a, 200) -#endif /* CUSTOMER_HW_SAMSUNG */ - #define DHD_PM_RESUME_WAIT_FOREVER(a) _DHD_PM_RESUME_WAIT(a, ~0) - #define DHD_PM_RESUME_RETURN_ERROR(a) do { \ - if (dhd_mmc_suspend) { \ - printf("mmc in suspend yet!!!: %s %d\n", \ - __FUNCTION__, __LINE__); \ - return a; \ - } \ - } while (0) - #define DHD_PM_RESUME_RETURN do { if (dhd_mmc_suspend) return; } while (0) - - #define DHD_SPINWAIT_SLEEP_INIT(a) DECLARE_WAIT_QUEUE_HEAD(a); - #define SPINWAIT_SLEEP(a, exp, us) do { \ - uint countdown = (us) + 9999; \ - while ((exp) && (countdown >= 10000)) { \ - wait_event_interruptible_timeout(a, FALSE, HZ/100); \ - countdown -= 10000; \ - } \ - } while (0) - - #else - - #define DHD_PM_RESUME_WAIT_INIT(a) - #define DHD_PM_RESUME_WAIT(a) - #define DHD_PM_RESUME_WAIT_FOREVER(a) - #define DHD_PM_RESUME_RETURN_ERROR(a) - #define DHD_PM_RESUME_RETURN - - #define DHD_SPINWAIT_SLEEP_INIT(a) - #define SPINWAIT_SLEEP(a, exp, us) do { \ - uint countdown = (us) + 9; \ - while ((exp) && (countdown >= 10)) { \ - OSL_DELAY(10); \ - countdown -= 10; \ - } \ - } while (0) - - #endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ -#ifndef DHDTHREAD -#undef SPINWAIT_SLEEP -#define SPINWAIT_SLEEP(a, exp, us) SPINWAIT(exp, us) -#endif /* DHDTHREAD */ -#define DHD_IF_VIF 0x01 /* Virtual IF (Hidden from user) */ - -unsigned long dhd_os_spin_lock(dhd_pub_t *pub); -void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags); - -/* Wakelock Functions */ -extern int dhd_os_wake_lock(dhd_pub_t *pub); -extern int dhd_os_wake_unlock(dhd_pub_t *pub); -extern int dhd_os_wake_lock_timeout(dhd_pub_t *pub); -extern int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val); - -inline static void MUTEX_LOCK_SOFTAP_SET_INIT(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_init(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_LOCK_SOFTAP_SET(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_lock(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -inline static void MUTEX_UNLOCK_SOFTAP_SET(dhd_pub_t * dhdp) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_unlock(&dhdp->wl_softap_lock); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -} - -#ifdef DHD_DEBUG_WAKE_LOCK -#define DHD_OS_WAKE_LOCK(pub) \ - do { \ - printf("call wake_lock: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_os_wake_lock(pub); \ - } while (0) -#define DHD_OS_WAKE_UNLOCK(pub) \ - do { \ - printf("call wake_unlock: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_os_wake_unlock(pub); \ - } while (0) -#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) \ - do { \ - printf("call wake_lock_timeout: %s %d\n", \ - __FUNCTION__, __LINE__); \ - dhd_os_wake_lock_timeout(pub); \ - } while (0) -#define DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(pub, val) \ - do { \ - printf("call wake_lock_timeout_enable[%d]: %s %d\n", \ - val, __FUNCTION__, __LINE__); \ - dhd_os_wake_lock_timeout_enable(pub, val); \ - } while (0) -#else -#define DHD_OS_WAKE_LOCK(pub) dhd_os_wake_lock(pub) -#define DHD_OS_WAKE_UNLOCK(pub) dhd_os_wake_unlock(pub) -#define DHD_OS_WAKE_LOCK_TIMEOUT(pub) dhd_os_wake_lock_timeout(pub) -#define DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(pub, val) dhd_os_wake_lock_timeout_enable(pub, val) -#endif /* DHD_DEBUG_WAKE_LOCK */ -#define DHD_PACKET_TIMEOUT_MS 1000 -#define DHD_EVENT_TIMEOUT_MS 1500 - -/* interface operations (register, remove) should be atomic, use this lock to prevent race - * condition among wifi on/off and interface operation functions - */ -void dhd_net_if_lock(struct net_device *dev); -void dhd_net_if_unlock(struct net_device *dev); - -typedef struct dhd_if_event { - uint8 ifidx; - uint8 action; - uint8 flags; - uint8 bssidx; - uint8 is_AP; -} dhd_if_event_t; - -typedef enum dhd_attach_states -{ - DHD_ATTACH_STATE_INIT = 0x0, - DHD_ATTACH_STATE_NET_ALLOC = 0x1, - DHD_ATTACH_STATE_DHD_ALLOC = 0x2, - DHD_ATTACH_STATE_ADD_IF = 0x4, - DHD_ATTACH_STATE_PROT_ATTACH = 0x8, - DHD_ATTACH_STATE_WL_ATTACH = 0x10, - DHD_ATTACH_STATE_THREADS_CREATED = 0x20, - DHD_ATTACH_STATE_WAKELOCKS_INIT = 0x40, - DHD_ATTACH_STATE_CFG80211 = 0x80, - DHD_ATTACH_STATE_EARLYSUSPEND_DONE = 0x100, - DHD_ATTACH_STATE_DONE = 0x200 -} dhd_attach_states_t; - -/* Value -1 means we are unsuccessful in creating the kthread. */ -#define DHD_PID_KT_INVALID -1 -/* Value -2 means we are unsuccessful in both creating the kthread and tasklet */ -#define DHD_PID_KT_TL_INVALID -2 - -/* - * Exported from dhd OS modules (dhd_linux/dhd_ndis) - */ - -/* To allow osl_attach/detach calls from os-independent modules */ -osl_t *dhd_osl_attach(void *pdev, uint bustype); -void dhd_osl_detach(osl_t *osh); - -/* Indication from bus module regarding presence/insertion of dongle. - * Return dhd_pub_t pointer, used as handle to OS module in later calls. - * Returned structure should have bus and prot pointers filled in. - * bus_hdrlen specifies required headroom for bus module header. - */ -extern dhd_pub_t *dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen); -#if defined(WLP2P) && defined(WL_CFG80211) -/* To allow attach/detach calls corresponding to p2p0 interface */ -extern int dhd_attach_p2p(dhd_pub_t *); -extern int dhd_detach_p2p(dhd_pub_t *); -#endif /* WLP2P && WL_CFG80211 */ -extern int dhd_net_attach(dhd_pub_t *dhdp, int idx); - -/* Indication from bus module regarding removal/absence of dongle */ -extern void dhd_detach(dhd_pub_t *dhdp); -extern void dhd_free(dhd_pub_t *dhdp); - -/* Indication from bus module to change flow-control state */ -extern void dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool on); - -extern bool dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec); - -/* Receive frame for delivery to OS. Callee disposes of rxp. */ -extern void dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *rxp, int numpkt, uint8 chan); - -/* Return pointer to interface name */ -extern char *dhd_ifname(dhd_pub_t *dhdp, int idx); - -/* Request scheduling of the bus dpc */ -extern void dhd_sched_dpc(dhd_pub_t *dhdp); - -/* Notify tx completion */ -extern void dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success); - -/* OS independent layer functions */ -extern int dhd_os_proto_block(dhd_pub_t * pub); -extern int dhd_os_proto_unblock(dhd_pub_t * pub); -extern int dhd_os_ioctl_resp_wait(dhd_pub_t * pub, uint * condition, bool * pending); -extern int dhd_os_ioctl_resp_wake(dhd_pub_t * pub); -extern unsigned int dhd_os_get_ioctl_resp_timeout(void); -extern void dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec); -extern void * dhd_os_open_image(char * filename); -extern int dhd_os_get_image_block(char * buf, int len, void * image); -extern void dhd_os_close_image(void * image); -extern void dhd_os_wd_timer(void *bus, uint wdtick); -extern void dhd_os_sdlock(dhd_pub_t * pub); -extern void dhd_os_sdunlock(dhd_pub_t * pub); -extern void dhd_os_sdlock_txq(dhd_pub_t * pub); -extern void dhd_os_sdunlock_txq(dhd_pub_t * pub); -extern void dhd_os_sdlock_rxq(dhd_pub_t * pub); -extern void dhd_os_sdunlock_rxq(dhd_pub_t * pub); -extern void dhd_os_sdlock_sndup_rxq(dhd_pub_t * pub); -extern void dhd_customer_gpio_wlan_ctrl(int onoff); -extern int dhd_custom_get_mac_address(unsigned char *buf); -extern void dhd_os_sdunlock_sndup_rxq(dhd_pub_t * pub); -extern void dhd_os_sdlock_eventq(dhd_pub_t * pub); -extern void dhd_os_sdunlock_eventq(dhd_pub_t * pub); -extern bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret); - -#ifdef PNO_SUPPORT -extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); -extern int dhd_pno_clean(dhd_pub_t *dhd); -extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, - ushort scan_fr, int pno_repeat, int pno_freq_expo_max); -extern int dhd_pno_get_status(dhd_pub_t *dhd); -extern int dhd_dev_pno_reset(struct net_device *dev); -extern int dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, - int nssid, ushort scan_fr, int pno_repeat, int pno_freq_expo_max); -extern int dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled); -extern int dhd_dev_get_pno_status(struct net_device *dev); -#endif /* PNO_SUPPORT */ - -#define DHD_UNICAST_FILTER_NUM 0 -#define DHD_BROADCAST_FILTER_NUM 1 -#define DHD_MULTICAST4_FILTER_NUM 2 -#define DHD_MULTICAST6_FILTER_NUM 3 -extern int net_os_set_packet_filter(struct net_device *dev, int val); -extern int net_os_rxfilter_add_remove(struct net_device *dev, int val, int num); - -extern int dhd_get_dtim_skip(dhd_pub_t *dhd); -extern bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd); - -#ifdef DHD_DEBUG -extern int write_to_file(dhd_pub_t *dhd, uint8 *buf, int size); -#endif /* DHD_DEBUG */ -#if defined(OOB_INTR_ONLY) -extern int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr); -#endif /* defined(OOB_INTR_ONLY) */ -extern void dhd_os_sdtxlock(dhd_pub_t * pub); -extern void dhd_os_sdtxunlock(dhd_pub_t * pub); - -typedef struct { - uint32 limit; /* Expiration time (usec) */ - uint32 increment; /* Current expiration increment (usec) */ - uint32 elapsed; /* Current elapsed time (usec) */ - uint32 tick; /* O/S tick time (usec) */ -} dhd_timeout_t; - -extern void dhd_timeout_start(dhd_timeout_t *tmo, uint usec); -extern int dhd_timeout_expired(dhd_timeout_t *tmo); - -extern int dhd_ifname2idx(struct dhd_info *dhd, char *name); -extern int dhd_net2idx(struct dhd_info *dhd, struct net_device *net); -extern struct net_device * dhd_idx2net(void *pub, int ifidx); -extern int wl_host_event(dhd_pub_t *dhd_pub, int *idx, void *pktdata, - wl_event_msg_t *, void **data_ptr); -extern void wl_event_to_host_order(wl_event_msg_t * evt); - -extern int dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len); -extern int dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, - int ifindex); - -extern void dhd_common_init(osl_t *osh); - -extern int dhd_do_driver_init(struct net_device *net); -extern int dhd_add_if(struct dhd_info *dhd, int ifidx, void *handle, - char *name, uint8 *mac_addr, uint32 flags, uint8 bssidx); -extern void dhd_del_if(struct dhd_info *dhd, int ifidx); - -extern void dhd_vif_add(struct dhd_info *dhd, int ifidx, char * name); -extern void dhd_vif_del(struct dhd_info *dhd, int ifidx); - -extern void dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx); -extern void dhd_vif_sendup(struct dhd_info *dhd, int ifidx, uchar *cp, int len); - - -/* Send packet to dongle via data channel */ -extern int dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pkt); - -/* send up locally generated event */ -extern void dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); -/* Send event to host */ -extern void dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data); -extern int dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag); -extern uint dhd_bus_status(dhd_pub_t *dhdp); -extern int dhd_bus_start(dhd_pub_t *dhdp); -extern int dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size); -extern void dhd_print_buf(void *pbuf, int len, int bytes_per_line); -extern bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval); - -#if defined(KEEP_ALIVE) -extern int dhd_keep_alive_onoff(dhd_pub_t *dhd); -#endif /* KEEP_ALIVE */ - -#ifdef ARP_OFFLOAD_SUPPORT -extern void dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode); -extern void dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable); -#endif /* ARP_OFFLOAD_SUPPORT */ - - -typedef enum cust_gpio_modes { - WLAN_RESET_ON, - WLAN_RESET_OFF, - WLAN_POWER_ON, - WLAN_POWER_OFF -} cust_gpio_modes_t; - -extern int wl_iw_iscan_set_scan_broadcast_prep(struct net_device *dev, uint flag); -extern int wl_iw_send_priv_event(struct net_device *dev, char *flag); -/* - * Insmod parameters for debug/test - */ - -/* Watchdog timer interval */ -extern uint dhd_watchdog_ms; - -#if defined(DHD_DEBUG) -/* Console output poll interval */ -extern uint dhd_console_ms; -extern uint wl_msg_level; -#endif /* defined(DHD_DEBUG) */ - -extern uint dhd_slpauto; - -/* Use interrupts */ -extern uint dhd_intr; - -/* Use polling */ -extern uint dhd_poll; - -/* ARP offload agent mode */ -extern uint dhd_arp_mode; - -/* ARP offload enable */ -extern uint dhd_arp_enable; - -/* Pkt filte enable control */ -extern uint dhd_pkt_filter_enable; - -/* Pkt filter init setup */ -extern uint dhd_pkt_filter_init; - -/* Pkt filter mode control */ -extern uint dhd_master_mode; - -/* Roaming mode control */ -extern uint dhd_roam_disable; - -/* Roaming mode control */ -extern uint dhd_radio_up; - -/* Initial idletime ticks (may be -1 for immediate idle, 0 for no idle) */ -extern int dhd_idletime; -#ifdef DHD_USE_IDLECOUNT -#define DHD_IDLETIME_TICKS 5 -#else -#define DHD_IDLETIME_TICKS 1 -#endif /* DHD_USE_IDLECOUNT */ - -/* SDIO Drive Strength */ -extern uint dhd_sdiod_drive_strength; - -/* Override to force tx queueing all the time */ -extern uint dhd_force_tx_queueing; -/* Default KEEP_ALIVE Period is 55 sec to prevent AP from sending Keep Alive probe frame */ -#ifdef KEEP_ALIVE_PACKET_PERIOD_30_SEC -#define KEEP_ALIVE_PERIOD 30000 -#else /* KEEP_ALIVE_PACKET_PERIOD_30_SEC */ -#define KEEP_ALIVE_PERIOD 55000 -#endif /* KEEP_ALIVE_PACKET_PERIOD_30_SEC */ -#define NULL_PKT_STR "null_pkt" - -#ifdef SDTEST -/* Echo packet generator (SDIO), pkts/s */ -extern uint dhd_pktgen; - -/* Echo packet len (0 => sawtooth, max 1800) */ -extern uint dhd_pktgen_len; -#define MAX_PKTGEN_LEN 1800 -#endif - - -/* optionally set by a module_param_string() */ -#define MOD_PARAM_PATHLEN 2048 -extern char fw_path[MOD_PARAM_PATHLEN]; -extern char nv_path[MOD_PARAM_PATHLEN]; - -#ifdef SOFTAP -extern char fw_path2[MOD_PARAM_PATHLEN]; -#endif - -/* Flag to indicate if we should download firmware on driver load */ -extern uint dhd_download_fw_on_driverload; - -#if defined(WL_CFG80211) && defined(CUSTOMER_HW_SAMSUNG) -/* CSP#505233: Flags to indicate if we distingish power off policy when - * user set the memu "Keep Wi-Fi on during sleep" to "Never" - */ -extern int sleep_never; -int dhd_deepsleep(struct net_device *dev, int flag); -#endif /* WL_CFG80211 && CUSTOMER_HW_SAMSUNG */ - -#ifdef BCM4334_CHECK_CHIP_REV -/* Check chip revision */ -extern uint g_chipver; -extern char chipver_tag[4]; -extern char fw_down_path[MOD_PARAM_PATHLEN]; -#endif - -/* For supporting multiple interfaces */ -#define DHD_MAX_IFS 16 -#define DHD_DEL_IF -0xe -#define DHD_BAD_IF -0xf - -#define WL_AUTO_ROAM_TRIGGER -75 - -#ifdef PROP_TXSTATUS -/* Please be mindful that total pkttag space is 32 octets only */ -typedef struct dhd_pkttag { - /* - b[11 ] - 1 = this packet was sent in response to one time packet request, - do not increment credit on status for this one. [WLFC_CTL_TYPE_MAC_REQUEST_PACKET]. - b[10 ] - 1 = signal-only-packet to firmware [i.e. nothing to piggyback on] - b[9 ] - 1 = packet is host->firmware (transmit direction) - - 0 = packet received from firmware (firmware->host) - b[8 ] - 1 = packet was sent due to credit_request (pspoll), - packet does not count against FIFO credit. - - 0 = normal transaction, packet counts against FIFO credit - b[7 ] - 1 = AP, 0 = STA - b[6:4] - AC FIFO number - b[3:0] - interface index - */ - uint16 if_flags; - /* destination MAC address for this packet so that not every - module needs to open the packet to find this - */ - uint8 dstn_ether[ETHER_ADDR_LEN]; - /* - This 32-bit goes from host to device for every packet. - */ - uint32 htod_tag; - /* bus specific stuff */ - union { - struct { - void* stuff; - uint32 thing1; - uint32 thing2; - } sd; - struct { - void* bus; - void* urb; - } usb; - } bus_specific; -} dhd_pkttag_t; - -#define DHD_PKTTAG_SET_H2DTAG(tag, h2dvalue) ((dhd_pkttag_t*)(tag))->htod_tag = (h2dvalue) -#define DHD_PKTTAG_H2DTAG(tag) (((dhd_pkttag_t*)(tag))->htod_tag) - -#define DHD_PKTTAG_IFMASK 0xf -#define DHD_PKTTAG_IFTYPE_MASK 0x1 -#define DHD_PKTTAG_IFTYPE_SHIFT 7 -#define DHD_PKTTAG_FIFO_MASK 0x7 -#define DHD_PKTTAG_FIFO_SHIFT 4 - -#define DHD_PKTTAG_SIGNALONLY_MASK 0x1 -#define DHD_PKTTAG_SIGNALONLY_SHIFT 10 - -#define DHD_PKTTAG_ONETIMEPKTRQST_MASK 0x1 -#define DHD_PKTTAG_ONETIMEPKTRQST_SHIFT 11 - -#define DHD_PKTTAG_PKTDIR_MASK 0x1 -#define DHD_PKTTAG_PKTDIR_SHIFT 9 - -#define DHD_PKTTAG_CREDITCHECK_MASK 0x1 -#define DHD_PKTTAG_CREDITCHECK_SHIFT 8 - -#define DHD_PKTTAG_INVALID_FIFOID 0x7 - -#define DHD_PKTTAG_SETFIFO(tag, fifo) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & ~(DHD_PKTTAG_FIFO_MASK << DHD_PKTTAG_FIFO_SHIFT)) | \ - (((fifo) & DHD_PKTTAG_FIFO_MASK) << DHD_PKTTAG_FIFO_SHIFT) -#define DHD_PKTTAG_FIFO(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_FIFO_SHIFT) & DHD_PKTTAG_FIFO_MASK) - -#define DHD_PKTTAG_SETIF(tag, if) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & ~DHD_PKTTAG_IFMASK) | ((if) & DHD_PKTTAG_IFMASK) -#define DHD_PKTTAG_IF(tag) (((dhd_pkttag_t*)(tag))->if_flags & DHD_PKTTAG_IFMASK) - -#define DHD_PKTTAG_SETIFTYPE(tag, isAP) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_IFTYPE_MASK << DHD_PKTTAG_IFTYPE_SHIFT)) | \ - (((isAP) & DHD_PKTTAG_IFTYPE_MASK) << DHD_PKTTAG_IFTYPE_SHIFT) -#define DHD_PKTTAG_IFTYPE(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_IFTYPE_SHIFT) & DHD_PKTTAG_IFTYPE_MASK) - -#define DHD_PKTTAG_SETCREDITCHECK(tag, check) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_CREDITCHECK_MASK << DHD_PKTTAG_CREDITCHECK_SHIFT)) | \ - (((check) & DHD_PKTTAG_CREDITCHECK_MASK) << DHD_PKTTAG_CREDITCHECK_SHIFT) -#define DHD_PKTTAG_CREDITCHECK(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_CREDITCHECK_SHIFT) & DHD_PKTTAG_CREDITCHECK_MASK) - -#define DHD_PKTTAG_SETPKTDIR(tag, dir) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_PKTDIR_MASK << DHD_PKTTAG_PKTDIR_SHIFT)) | \ - (((dir) & DHD_PKTTAG_PKTDIR_MASK) << DHD_PKTTAG_PKTDIR_SHIFT) -#define DHD_PKTTAG_PKTDIR(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_PKTDIR_SHIFT) & DHD_PKTTAG_PKTDIR_MASK) - -#define DHD_PKTTAG_SETSIGNALONLY(tag, signalonly) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_SIGNALONLY_MASK << DHD_PKTTAG_SIGNALONLY_SHIFT)) | \ - (((signalonly) & DHD_PKTTAG_SIGNALONLY_MASK) << DHD_PKTTAG_SIGNALONLY_SHIFT) -#define DHD_PKTTAG_SIGNALONLY(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_SIGNALONLY_SHIFT) & DHD_PKTTAG_SIGNALONLY_MASK) - -#define DHD_PKTTAG_SETONETIMEPKTRQST(tag) ((dhd_pkttag_t*)(tag))->if_flags = \ - (((dhd_pkttag_t*)(tag))->if_flags & \ - ~(DHD_PKTTAG_ONETIMEPKTRQST_MASK << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT)) | \ - (1 << DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) -#define DHD_PKTTAG_ONETIMEPKTRQST(tag) ((((dhd_pkttag_t*)(tag))->if_flags >> \ - DHD_PKTTAG_ONETIMEPKTRQST_SHIFT) & DHD_PKTTAG_ONETIMEPKTRQST_MASK) - -#define DHD_PKTTAG_SETDSTN(tag, dstn_MAC_ea) memcpy(((dhd_pkttag_t*)((tag)))->dstn_ether, \ - (dstn_MAC_ea), ETHER_ADDR_LEN) -#define DHD_PKTTAG_DSTN(tag) ((dhd_pkttag_t*)(tag))->dstn_ether - -typedef int (*f_commitpkt_t)(void* ctx, void* p); - -#ifdef PROP_TXSTATUS_DEBUG -#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do { (entry)->closed_ct++; } while (0) -#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do { (entry)->opened_ct++; } while (0) -#else -#define DHD_WLFC_CTRINC_MAC_CLOSE(entry) do {} while (0) -#define DHD_WLFC_CTRINC_MAC_OPEN(entry) do {} while (0) -#endif - -#endif /* PROP_TXSTATUS */ - -extern void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar); -extern void dhd_wait_event_wakeup(dhd_pub_t*dhd); - -#define IFLOCK_INIT(lock) *lock = 0 -#define IFLOCK(lock) while (InterlockedCompareExchange((lock), 1, 0)) \ - NdisStallExecution(1); -#define IFUNLOCK(lock) InterlockedExchange((lock), 0) -#define IFLOCK_FREE(lock) - -#ifdef PNO_SUPPORT -extern int dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled); -extern int dhd_pnoenable(dhd_pub_t *dhd, int pfn_enabled); -extern int dhd_pno_clean(dhd_pub_t *dhd); -extern int dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, - ushort scan_fr, int pno_repeat, int pno_freq_expo_max); -extern int dhd_pno_get_status(dhd_pub_t *dhd); -extern int dhd_pno_set_add(dhd_pub_t *dhd, wl_pfn_t *netinfo, int nssid, ushort scan_fr, - ushort slowscan_fr, uint8 pno_repeat, uint8 pno_freq_expo_max, int16 flags); -extern int dhd_pno_cfg(dhd_pub_t *dhd, wl_pfn_cfg_t *pcfg); -extern int dhd_pno_suspend(dhd_pub_t *dhd, int pfn_suspend); -#endif /* PNO_SUPPORT */ -#ifdef ARP_OFFLOAD_SUPPORT -#define MAX_IPV4_ENTRIES 8 -/* dhd_commn arp offload wrapers */ -void dhd_aoe_hostip_clr(dhd_pub_t *dhd); -void dhd_aoe_arp_clr(dhd_pub_t *dhd); -int dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen); -void dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr); -#endif /* ARP_OFFLOAD_SUPPORT */ - -#ifdef RDWR_KORICS_MACADDR -extern int -dhd_write_rdwr_korics_macaddr(struct dhd_info *dhd, struct ether_addr *mac); -#endif - -#endif /* _dhd_h_ */ diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_bta.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_bta.c deleted file mode 100644 index 52b51cc..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_bta.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * BT-AMP support routines - * - * Copyright (C) 1999-2011, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_bta.c 303834 2011-12-20 06:17:39Z $ - */ -#ifndef WLBTAMP -#error "WLBTAMP is not defined" -#endif /* WLBTAMP */ - -#include <typedefs.h> -#include <osl.h> -#include <bcmcdc.h> -#include <bcmutils.h> -#include <bcmendian.h> -#include <proto/802.11.h> -#include <proto/802.11_bta.h> -#include <proto/bt_amp_hci.h> -#include <dngl_stats.h> -#include <dhd.h> -#include <dhd_bus.h> -#include <dhd_proto.h> -#include <dhdioctl.h> -#include <dhd_dbg.h> - -#include <dhd_bta.h> - - -#ifdef SEND_HCI_CMD_VIA_IOCTL -#define BTA_HCI_CMD_MAX_LEN HCI_CMD_PREAMBLE_SIZE + HCI_CMD_DATA_SIZE - -/* Send HCI cmd via wl iovar HCI_cmd to the dongle. */ -int -dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) -{ - amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; - uint8 buf[BTA_HCI_CMD_MAX_LEN + 16]; - uint len = sizeof(buf); - wl_ioctl_t ioc; - - if (cmd_len < HCI_CMD_PREAMBLE_SIZE) - return BCME_BADLEN; - - if ((uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE > cmd_len) - return BCME_BADLEN; - - len = bcm_mkiovar("HCI_cmd", - (char *)cmd, (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE, (char *)buf, len); - - - memset(&ioc, 0, sizeof(ioc)); - - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = len; - ioc.set = TRUE; - - return dhd_wl_ioctl(pub, &ioc, ioc.buf, ioc.len); -} -#else /* !SEND_HCI_CMD_VIA_IOCTL */ - -static void -dhd_bta_flush_hcidata(dhd_pub_t *pub, uint16 llh) -{ - int prec; - struct pktq *q; - uint count = 0; - - q = dhd_bus_txq(pub->bus); - if (q == NULL) - return; - - DHD_BTA(("dhd: flushing HCI ACL data for logical link %u...\n", llh)); - - dhd_os_sdlock_txq(pub); - - /* Walk through the txq and toss all HCI ACL data packets */ - PKTQ_PREC_ITER(q, prec) { - void *head_pkt = NULL; - - while (pktq_ppeek(q, prec) != head_pkt) { - void *pkt = pktq_pdeq(q, prec); - int ifidx; - - PKTPULL(pub->osh, pkt, dhd_bus_hdrlen(pub->bus)); - dhd_prot_hdrpull(pub, &ifidx, pkt, NULL, NULL); - - if (PKTLEN(pub->osh, pkt) >= RFC1042_HDR_LEN) { - struct ether_header *eh = - (struct ether_header *)PKTDATA(pub->osh, pkt); - - if (ntoh16(eh->ether_type) < ETHER_TYPE_MIN) { - struct dot11_llc_snap_header *lsh = - (struct dot11_llc_snap_header *)&eh[1]; - - if (bcmp(lsh, BT_SIG_SNAP_MPROT, - DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && - ntoh16(lsh->type) == BTA_PROT_L2CAP) { - amp_hci_ACL_data_t *ACL_data = - (amp_hci_ACL_data_t *)&lsh[1]; - uint16 handle = ltoh16(ACL_data->handle); - - if (HCI_ACL_DATA_HANDLE(handle) == llh) { - PKTFREE(pub->osh, pkt, TRUE); - count ++; - continue; - } - } - } - } - - dhd_prot_hdrpush(pub, ifidx, pkt); - PKTPUSH(pub->osh, pkt, dhd_bus_hdrlen(pub->bus)); - - if (head_pkt == NULL) - head_pkt = pkt; - pktq_penq(q, prec, pkt); - } - } - - dhd_os_sdunlock_txq(pub); - - DHD_BTA(("dhd: flushed %u packet(s) for logical link %u...\n", count, llh)); -} - -/* Handle HCI cmd locally. - * Return 0: continue to send the cmd across SDIO - * < 0: stop, fail - * > 0: stop, succuess - */ -static int -_dhd_bta_docmd(dhd_pub_t *pub, amp_hci_cmd_t *cmd) -{ - int status = 0; - - switch (ltoh16_ua((uint8 *)&cmd->opcode)) { - case HCI_Enhanced_Flush: { - eflush_cmd_parms_t *cmdparms = (eflush_cmd_parms_t *)cmd->parms; - dhd_bta_flush_hcidata(pub, ltoh16_ua(cmdparms->llh)); - break; - } - default: - break; - } - - return status; -} - -/* Send HCI cmd encapsulated in BT-SIG frame via data channel to the dongle. */ -int -dhd_bta_docmd(dhd_pub_t *pub, void *cmd_buf, uint cmd_len) -{ - amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)cmd_buf; - struct ether_header *eh; - struct dot11_llc_snap_header *lsh; - osl_t *osh = pub->osh; - uint len; - void *p; - int status; - - if (cmd_len < HCI_CMD_PREAMBLE_SIZE) { - DHD_ERROR(("dhd_bta_docmd: short command, cmd_len %u\n", cmd_len)); - return BCME_BADLEN; - } - - if ((len = (uint)cmd->plen + HCI_CMD_PREAMBLE_SIZE) > cmd_len) { - DHD_ERROR(("dhd_bta_docmd: malformed command, len %u cmd_len %u\n", - len, cmd_len)); - /* return BCME_BADLEN; */ - } - - p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); - if (p == NULL) { - DHD_ERROR(("dhd_bta_docmd: out of memory\n")); - return BCME_NOMEM; - } - - - /* intercept and handle the HCI cmd locally */ - if ((status = _dhd_bta_docmd(pub, cmd)) > 0) - return 0; - else if (status < 0) - return status; - - /* copy in HCI cmd */ - PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); - bcopy(cmd, PKTDATA(osh, p), len); - - /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ - PKTPUSH(osh, p, RFC1042_HDR_LEN); - eh = (struct ether_header *)PKTDATA(osh, p); - bzero(eh->ether_dhost, ETHER_ADDR_LEN); - ETHER_SET_LOCALADDR(eh->ether_dhost); - bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); - eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); - lsh = (struct dot11_llc_snap_header *)&eh[1]; - bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); - lsh->type = 0; - - return dhd_sendpkt(pub, 0, p); -} -#endif /* !SEND_HCI_CMD_VIA_IOCTL */ - -/* Send HCI ACL data to dongle via data channel */ -int -dhd_bta_tx_hcidata(dhd_pub_t *pub, void *data_buf, uint data_len) -{ - amp_hci_ACL_data_t *data = (amp_hci_ACL_data_t *)data_buf; - struct ether_header *eh; - struct dot11_llc_snap_header *lsh; - osl_t *osh = pub->osh; - uint len; - void *p; - - if (data_len < HCI_ACL_DATA_PREAMBLE_SIZE) { - DHD_ERROR(("dhd_bta_tx_hcidata: short data_buf, data_len %u\n", data_len)); - return BCME_BADLEN; - } - - if ((len = (uint)ltoh16(data->dlen) + HCI_ACL_DATA_PREAMBLE_SIZE) > data_len) { - DHD_ERROR(("dhd_bta_tx_hcidata: malformed hci data, len %u data_len %u\n", - len, data_len)); - /* return BCME_BADLEN; */ - } - - p = PKTGET(osh, pub->hdrlen + RFC1042_HDR_LEN + len, TRUE); - if (p == NULL) { - DHD_ERROR(("dhd_bta_tx_hcidata: out of memory\n")); - return BCME_NOMEM; - } - - - /* copy in HCI ACL data header and HCI ACL data */ - PKTPULL(osh, p, pub->hdrlen + RFC1042_HDR_LEN); - bcopy(data, PKTDATA(osh, p), len); - - /* copy in partial Ethernet header with BT-SIG LLC/SNAP header */ - PKTPUSH(osh, p, RFC1042_HDR_LEN); - eh = (struct ether_header *)PKTDATA(osh, p); - bzero(eh->ether_dhost, ETHER_ADDR_LEN); - bcopy(&pub->mac, eh->ether_shost, ETHER_ADDR_LEN); - eh->ether_type = hton16(len + DOT11_LLC_SNAP_HDR_LEN); - lsh = (struct dot11_llc_snap_header *)&eh[1]; - bcopy(BT_SIG_SNAP_MPROT, lsh, DOT11_LLC_SNAP_HDR_LEN - 2); - lsh->type = HTON16(BTA_PROT_L2CAP); - - return dhd_sendpkt(pub, 0, p); -} - -/* txcomplete callback */ -void -dhd_bta_tx_hcidata_complete(dhd_pub_t *dhdp, void *txp, bool success) -{ - uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, txp); - amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)(pktdata + RFC1042_HDR_LEN); - uint16 handle = ltoh16(ACL_data->handle); - uint16 llh = HCI_ACL_DATA_HANDLE(handle); - - wl_event_msg_t event; - uint8 data[HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t)]; - amp_hci_event_t *evt; - num_completed_data_blocks_evt_parms_t *parms; - - uint16 len = HCI_EVT_PREAMBLE_SIZE + sizeof(num_completed_data_blocks_evt_parms_t); - - /* update the event struct */ - memset(&event, 0, sizeof(event)); - event.version = hton16(BCM_EVENT_MSG_VERSION); - event.event_type = hton32(WLC_E_BTA_HCI_EVENT); - event.status = 0; - event.reason = 0; - event.auth_type = 0; - event.datalen = hton32(len); - event.flags = 0; - - /* generate Number of Completed Blocks event */ - evt = (amp_hci_event_t *)data; - evt->ecode = HCI_Number_of_Completed_Data_Blocks; - evt->plen = sizeof(num_completed_data_blocks_evt_parms_t); - - parms = (num_completed_data_blocks_evt_parms_t *)evt->parms; - htol16_ua_store(dhdp->maxdatablks, (uint8 *)&parms->num_blocks); - parms->num_handles = 1; - htol16_ua_store(llh, (uint8 *)&parms->completed[0].handle); - parms->completed[0].pkts = 1; - parms->completed[0].blocks = 1; - - dhd_sendup_event_common(dhdp, &event, data); -} - -/* event callback */ -void -dhd_bta_doevt(dhd_pub_t *dhdp, void *data_buf, uint data_len) -{ - amp_hci_event_t *evt = (amp_hci_event_t *)data_buf; - - switch (evt->ecode) { - case HCI_Command_Complete: { - cmd_complete_parms_t *parms = (cmd_complete_parms_t *)evt->parms; - switch (ltoh16_ua((uint8 *)&parms->opcode)) { - case HCI_Read_Data_Block_Size: { - read_data_block_size_evt_parms_t *parms2 = - (read_data_block_size_evt_parms_t *)parms->parms; - dhdp->maxdatablks = ltoh16_ua((uint8 *)&parms2->data_block_num); - break; - } - } - break; - } - - case HCI_Flush_Occurred: { - flush_occurred_evt_parms_t *evt_parms = (flush_occurred_evt_parms_t *)evt->parms; - dhd_bta_flush_hcidata(dhdp, ltoh16_ua((uint8 *)&evt_parms->handle)); - break; - } - default: - break; - } -} diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_bta.h b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_bta.h deleted file mode 100644 index 0b18cdd..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_bta.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * BT-AMP support routines - * - * Copyright (C) 1999-2011, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_bta.h 291086 2011-10-21 01:17:24Z $ - */ -#ifndef __dhd_bta_h__ -#define __dhd_bta_h__ - -struct dhd_pub; - -extern int dhd_bta_docmd(struct dhd_pub *pub, void *cmd_buf, uint cmd_len); - -extern void dhd_bta_doevt(struct dhd_pub *pub, void *data_buf, uint data_len); - -extern int dhd_bta_tx_hcidata(struct dhd_pub *pub, void *data_buf, uint data_len); -extern void dhd_bta_tx_hcidata_complete(struct dhd_pub *dhdp, void *txp, bool success); - - -#endif /* __dhd_bta_h__ */ diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_bus.h b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_bus.h deleted file mode 100644 index 6774b65..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_bus.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Header file describing the internal (inter-module) DHD interfaces. - * - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2011, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_bus.h 291086 2011-10-21 01:17:24Z $ - */ - -#ifndef _dhd_bus_h_ -#define _dhd_bus_h_ - -/* - * Exported from dhd bus module (dhd_usb, dhd_sdio) - */ - -/* Indicate (dis)interest in finding dongles. */ -extern int dhd_bus_register(void); -extern void dhd_bus_unregister(void); - -/* Download firmware image and nvram image */ -extern bool dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, - char *fw_path, char *nv_path); - -/* Stop bus module: clear pending frames, disable data flow */ -extern void dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex); - -/* Initialize bus module: prepare for communication w/dongle */ -extern int dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex); - -/* Get the Bus Idle Time */ -extern void dhd_bus_getidletime(dhd_pub_t *dhdp, int *idletime); - -/* Set the Bus Idle Time */ -extern void dhd_bus_setidletime(dhd_pub_t *dhdp, int idle_time); - -/* Send a data frame to the dongle. Callee disposes of txp. */ -extern int dhd_bus_txdata(struct dhd_bus *bus, void *txp); - -/* Send/receive a control message to/from the dongle. - * Expects caller to enforce a single outstanding transaction. - */ -extern int dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen); -extern int dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen); - -/* Watchdog timer function */ -extern bool dhd_bus_watchdog(dhd_pub_t *dhd); -extern void dhd_disable_intr(dhd_pub_t *dhd); - -#if defined(DHD_DEBUG) -/* Device console input function */ -extern int dhd_bus_console_in(dhd_pub_t *dhd, uchar *msg, uint msglen); -#endif /* defined(DHD_DEBUG) */ - -/* Deferred processing for the bus, return TRUE requests reschedule */ -extern bool dhd_bus_dpc(struct dhd_bus *bus); -extern void dhd_bus_isr(bool * InterruptRecognized, bool * QueueMiniportHandleInterrupt, void *arg); - - -/* Check for and handle local prot-specific iovar commands */ -extern int dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set); - -/* Add bus dump output to a buffer */ -extern void dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); - -/* Clear any bus counters */ -extern void dhd_bus_clearcounts(dhd_pub_t *dhdp); - -/* return the dongle chipid */ -extern uint dhd_bus_chip(struct dhd_bus *bus); - -/* Set user-specified nvram parameters. */ -extern void dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params); - -extern void *dhd_bus_pub(struct dhd_bus *bus); -extern void *dhd_bus_txq(struct dhd_bus *bus); -extern uint dhd_bus_hdrlen(struct dhd_bus *bus); - -#define DHD_SET_BUS_STATE_DOWN(_bus) do { \ - (_bus)->dhd->busstate = DHD_BUS_DOWN; \ -} while (0) -/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ -extern int dhd_bus_reg_sdio_notify(void* semaphore); -extern void dhd_bus_unreg_sdio_notify(void); - -#endif /* _dhd_bus_h_ */ diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_cdc.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_cdc.c deleted file mode 100644 index 0cb4fb4..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_cdc.c +++ /dev/null @@ -1,2936 +0,0 @@ -/* - * DHD Protocol Module for CDC and BDC. - * - * Copyright (C) 1999-2012, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_cdc.c 304241 2011-12-21 16:43:50Z $ - * - * BDC is like CDC, except it includes a header for data packets to convey - * packet priority over the bus, and flags (e.g. to indicate checksum status - * for dongle offload.) - */ - -#include <typedefs.h> -#include <osl.h> - -#include <bcmutils.h> -#include <bcmcdc.h> -#include <bcmendian.h> - -#include <dngl_stats.h> -#include <dhd.h> -#include <dhd_proto.h> -#include <dhd_bus.h> -#include <dhd_dbg.h> - - -#ifdef PROP_TXSTATUS -#include <wlfc_proto.h> -#include <dhd_wlfc.h> -#endif - - -#define RETRIES 2 /* # of retries to retrieve matching ioctl response */ -#define BUS_HEADER_LEN (16+DHD_SDALIGN) /* Must be at least SDPCM_RESERVE - * defined in dhd_sdio.c (amount of header tha might be added) - * plus any space that might be needed for alignment padding. - */ -#define ROUND_UP_MARGIN 2048 /* Biggest SDIO block size possible for - * round off at the end of buffer - */ - -#define BUS_RETRIES 1 /* # of retries before aborting a bus tx operation */ - -#ifdef PROP_TXSTATUS -typedef struct dhd_wlfc_commit_info { - uint8 needs_hdr; - uint8 ac_fifo_credit_spent; - ewlfc_packet_state_t pkt_type; - wlfc_mac_descriptor_t* mac_entry; - void* p; -} dhd_wlfc_commit_info_t; -#endif /* PROP_TXSTATUS */ - -#ifdef VSDB_DYNAMIC_F2_BLKSIZE -extern uint sd_f2_blocksize; -extern int -dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size); -#endif -typedef struct dhd_prot { - uint16 reqid; - uint8 pending; - uint32 lastcmd; - uint8 bus_header[BUS_HEADER_LEN]; - cdc_ioctl_t msg; - unsigned char buf[WLC_IOCTL_MAXLEN + ROUND_UP_MARGIN]; -} dhd_prot_t; - - -static int -dhdcdc_msg(dhd_pub_t *dhd) -{ - int err = 0; - dhd_prot_t *prot = dhd->prot; - int len = ltoh32(prot->msg.len) + sizeof(cdc_ioctl_t); - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - DHD_OS_WAKE_LOCK(dhd); - - /* NOTE : cdc->msg.len holds the desired length of the buffer to be - * returned. Only up to CDC_MAX_MSG_SIZE of this buffer area - * is actually sent to the dongle - */ - if (len > CDC_MAX_MSG_SIZE) - len = CDC_MAX_MSG_SIZE; - - /* Send request */ - err = dhd_bus_txctl(dhd->bus, (uchar*)&prot->msg, len); - - DHD_OS_WAKE_UNLOCK(dhd); - return err; -} - -static int -dhdcdc_cmplt(dhd_pub_t *dhd, uint32 id, uint32 len) -{ - int ret; - int cdc_len = len + sizeof(cdc_ioctl_t); - dhd_prot_t *prot = dhd->prot; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#ifdef CUSTOMER_HW_SAMSUNG - DHD_OS_WAKE_LOCK(dhd); -#endif /* CUSTOMER_HW_SAMSUNG */ - do { - ret = dhd_bus_rxctl(dhd->bus, (uchar*)&prot->msg, cdc_len); - if (ret < 0) - break; - } while (CDC_IOC_ID(ltoh32(prot->msg.flags)) != id); - -#ifdef CUSTOMER_HW_SAMSUNG - DHD_OS_WAKE_UNLOCK(dhd); -#endif /* CUSTOMER_HW_SAMSUNG */ - return ret; -} - -static int -dhdcdc_query_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) -{ - dhd_prot_t *prot = dhd->prot; - cdc_ioctl_t *msg = &prot->msg; - void *info; - int ret = 0, retries = 0; - uint32 id, flags = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); - - - /* Respond "bcmerror" and "bcmerrorstr" with local cache */ - if (cmd == WLC_GET_VAR && buf) - { - if (!strcmp((char *)buf, "bcmerrorstr")) - { - strncpy((char *)buf, bcmerrorstr(dhd->dongle_error), BCME_STRLEN); - goto done; - } - else if (!strcmp((char *)buf, "bcmerror")) - { - *(int *)buf = dhd->dongle_error; - goto done; - } - } - - memset(msg, 0, sizeof(cdc_ioctl_t)); - - msg->cmd = htol32(cmd); - msg->len = htol32(len); - msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); - CDC_SET_IF_IDX(msg, ifidx); - /* add additional action bits */ - action &= WL_IOCTL_ACTION_MASK; - msg->flags |= (action << CDCF_IOC_ACTION_SHIFT); - msg->flags = htol32(msg->flags); - - if (buf) - memcpy(prot->buf, buf, len); - - if ((ret = dhdcdc_msg(dhd)) < 0) { - if (!dhd->hang_was_sent) - DHD_ERROR(("dhdcdc_query_ioctl: dhdcdc_msg failed w/status %d\n", ret)); - goto done; - } - -retry: - /* wait for interrupt and get first fragment */ - if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) - goto done; - - flags = ltoh32(msg->flags); - id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; - - if ((id < prot->reqid) && (++retries < RETRIES)) - goto retry; - if (id != prot->reqid) { - DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", - dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); - ret = -EINVAL; - goto done; - } - - /* Check info buffer */ - info = (void*)&msg[1]; - - /* Copy info buffer */ - if (buf) - { - if (ret < (int)len) - len = ret; - memcpy(buf, info, len); - } - - /* Check the ERROR flag */ - if (flags & CDCF_IOC_ERROR) - { - ret = ltoh32(msg->status); - /* Cache error from dongle */ - dhd->dongle_error = ret; - } - -done: - return ret; -} - -#ifdef CONFIG_CONTROL_PM -extern bool g_pm_control; -#endif - -static int -dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len, uint8 action) -{ - dhd_prot_t *prot = dhd->prot; - cdc_ioctl_t *msg = &prot->msg; - int ret = 0; - uint32 flags, id; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_CTL(("%s: cmd %d len %d\n", __FUNCTION__, cmd, len)); - - if (dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); - return -EIO; - } - - /* don't talk to the dongle if fw is about to be reloaded */ - if (dhd->hang_was_sent) { - DHD_ERROR(("%s: HANG was sent up earlier. Not talking to the chip\n", - __FUNCTION__)); - return -EIO; - } -#ifdef CONFIG_CONTROL_PM - if ((g_pm_control == TRUE) && (cmd == WLC_SET_PM)) - { - DHD_ERROR(("SET PM ignored!!!!!!!!!!!!!!!!!!!!!!\n")); - goto done; - } -#endif - - memset(msg, 0, sizeof(cdc_ioctl_t)); - - msg->cmd = htol32(cmd); - msg->len = htol32(len); - msg->flags = (++prot->reqid << CDCF_IOC_ID_SHIFT); - CDC_SET_IF_IDX(msg, ifidx); - /* add additional action bits */ - action &= WL_IOCTL_ACTION_MASK; - msg->flags |= (action << CDCF_IOC_ACTION_SHIFT) | CDCF_IOC_SET; - msg->flags = htol32(msg->flags); - - if (buf) - memcpy(prot->buf, buf, len); - - if ((ret = dhdcdc_msg(dhd)) < 0) { - DHD_ERROR(("%s: dhdcdc_msg failed w/status %d\n", __FUNCTION__, ret)); - goto done; - } - - if ((ret = dhdcdc_cmplt(dhd, prot->reqid, len)) < 0) - goto done; - - flags = ltoh32(msg->flags); - id = (flags & CDCF_IOC_ID_MASK) >> CDCF_IOC_ID_SHIFT; - - if (id != prot->reqid) { - DHD_ERROR(("%s: %s: unexpected request id %d (expected %d)\n", - dhd_ifname(dhd, ifidx), __FUNCTION__, id, prot->reqid)); - ret = -EINVAL; - goto done; - } - - /* Check the ERROR flag */ - if (flags & CDCF_IOC_ERROR) - { - ret = ltoh32(msg->status); - /* Cache error from dongle */ - dhd->dongle_error = ret; - } - -done: - return ret; -} - - -int -dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len) -{ - dhd_prot_t *prot = dhd->prot; - int ret = -1; - uint8 action; -#if defined(NDIS630) - bool acquired = FALSE; -#endif - - if ((dhd->busstate == DHD_BUS_DOWN) || dhd->hang_was_sent) { - DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); - goto done; - } -#if defined(NDIS630) - if (dhd_os_proto_block(dhd)) - { - acquired = TRUE; - } - else - { - /* attempt to acquire protocol mutex timed out. */ - ret = -1; - return ret; - } -#endif /* NDIS630 */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(len <= WLC_IOCTL_MAXLEN); - - if (len > WLC_IOCTL_MAXLEN) - goto done; - - if (prot->pending == TRUE) { - DHD_ERROR(("CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n", - ioc->cmd, (unsigned long)ioc->cmd, prot->lastcmd, - (unsigned long)prot->lastcmd)); - if ((ioc->cmd == WLC_SET_VAR) || (ioc->cmd == WLC_GET_VAR)) { - DHD_TRACE(("iovar cmd=%s\n", (char*)buf)); - } - goto done; - } - - prot->pending = TRUE; - prot->lastcmd = ioc->cmd; - action = ioc->set; - if (action & WL_IOCTL_ACTION_SET) - ret = dhdcdc_set_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); - else { - ret = dhdcdc_query_ioctl(dhd, ifidx, ioc->cmd, buf, len, action); - if (ret > 0) - ioc->used = ret - sizeof(cdc_ioctl_t); - } - - /* Too many programs assume ioctl() returns 0 on success */ - if (ret >= 0) - ret = 0; - else { - cdc_ioctl_t *msg = &prot->msg; - ioc->needed = ltoh32(msg->len); /* len == needed when set/query fails from dongle */ - } - - /* Intercept the wme_dp ioctl here */ - if ((!ret) && (ioc->cmd == WLC_SET_VAR) && (!strcmp(buf, "wme_dp"))) { - int slen, val = 0; - - slen = strlen("wme_dp") + 1; - if (len >= (int)(slen + sizeof(int))) - bcopy(((char *)buf + slen), &val, sizeof(int)); - dhd->wme_dp = (uint8) ltoh32(val); - } - - prot->pending = FALSE; - -done: -#if defined(NDIS630) - if (acquired) - dhd_os_proto_unblock(dhd); -#endif - return ret; -} - -int -dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - return BCME_UNSUPPORTED; -} - -#ifdef PROP_TXSTATUS -void -dhd_wlfc_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - int i; - uint8* ea; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhdp->wlfc_state; - wlfc_hanger_t* h; - wlfc_mac_descriptor_t* mac_table; - wlfc_mac_descriptor_t* interfaces; - char* iftypes[] = {"STA", "AP", "WDS", "p2pGO", "p2pCL"}; - - if (wlfc == NULL) { - bcm_bprintf(strbuf, "wlfc not initialized yet\n"); - return; - } - h = (wlfc_hanger_t*)wlfc->hanger; - if (h == NULL) { - bcm_bprintf(strbuf, "wlfc-hanger not initialized yet\n"); - } - - mac_table = wlfc->destination_entries.nodes; - interfaces = wlfc->destination_entries.interfaces; - bcm_bprintf(strbuf, "---- wlfc stats ----\n"); - if (h) { - bcm_bprintf(strbuf, "wlfc hanger (pushed,popped,f_push," - "f_pop,f_slot, pending) = (%d,%d,%d,%d,%d,%d)\n", - h->pushed, - h->popped, - h->failed_to_push, - h->failed_to_pop, - h->failed_slotfind, - (h->pushed - h->popped)); - } - - bcm_bprintf(strbuf, "wlfc fail(tlv,credit_rqst,mac_update,psmode_update), " - "(dq_full,sendq_full, rollback_fail) = (%d,%d,%d,%d), (%d,%d,%d)\n", - wlfc->stats.tlv_parse_failed, - wlfc->stats.credit_request_failed, - wlfc->stats.mac_update_failed, - wlfc->stats.psmode_update_failed, - wlfc->stats.delayq_full_error, - wlfc->stats.sendq_full_error, - wlfc->stats.rollback_failed); - - bcm_bprintf(strbuf, "SENDQ (len,credit,sent) " - "(AC0[%d,%d,%d],AC1[%d,%d,%d],AC2[%d,%d,%d],AC3[%d,%d,%d],BC_MC[%d,%d,%d])\n", - wlfc->SENDQ.q[0].len, wlfc->FIFO_credit[0], wlfc->stats.sendq_pkts[0], - wlfc->SENDQ.q[1].len, wlfc->FIFO_credit[1], wlfc->stats.sendq_pkts[1], - wlfc->SENDQ.q[2].len, wlfc->FIFO_credit[2], wlfc->stats.sendq_pkts[2], - wlfc->SENDQ.q[3].len, wlfc->FIFO_credit[3], wlfc->stats.sendq_pkts[3], - wlfc->SENDQ.q[4].len, wlfc->FIFO_credit[4], wlfc->stats.sendq_pkts[4]); - -#ifdef PROP_TXSTATUS_DEBUG - bcm_bprintf(strbuf, "SENDQ dropped: AC[0-3]:(%d,%d,%d,%d), (bcmc,atim):(%d,%d)\n", - wlfc->stats.dropped_qfull[0], wlfc->stats.dropped_qfull[1], - wlfc->stats.dropped_qfull[2], wlfc->stats.dropped_qfull[3], - wlfc->stats.dropped_qfull[4], wlfc->stats.dropped_qfull[5]); -#endif - - bcm_bprintf(strbuf, "\n"); - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - if (interfaces[i].occupied) { - char* iftype_desc; - - if (interfaces[i].iftype > WLC_E_IF_ROLE_P2P_CLIENT) - iftype_desc = "<Unknown"; - else - iftype_desc = iftypes[interfaces[i].iftype]; - - ea = interfaces[i].ea; - bcm_bprintf(strbuf, "INTERFACE[%d].ea = " - "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d, type: %s" - "netif_flow_control:%s\n", i, - ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], - interfaces[i].interface_id, - iftype_desc, ((wlfc->hostif_flow_state[i] == OFF) - ? " OFF":" ON")); - - bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ(len,state,credit)" - "= (%d,%s,%d)\n", - i, - interfaces[i].psq.len, - ((interfaces[i].state == - WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), - interfaces[i].requested_credit); - - bcm_bprintf(strbuf, "INTERFACE[%d].DELAYQ" - "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " - "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", - i, - interfaces[i].psq.q[0].len, - interfaces[i].psq.q[1].len, - interfaces[i].psq.q[2].len, - interfaces[i].psq.q[3].len, - interfaces[i].psq.q[4].len, - interfaces[i].psq.q[5].len, - interfaces[i].psq.q[6].len, - interfaces[i].psq.q[7].len); - } - } - - bcm_bprintf(strbuf, "\n"); - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (mac_table[i].occupied) { - ea = mac_table[i].ea; - bcm_bprintf(strbuf, "MAC_table[%d].ea = " - "[%02x:%02x:%02x:%02x:%02x:%02x], if:%d\n", i, - ea[0], ea[1], ea[2], ea[3], ea[4], ea[5], - mac_table[i].interface_id); - - bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ(len,state,credit)" - "= (%d,%s,%d)\n", - i, - mac_table[i].psq.len, - ((mac_table[i].state == - WLFC_STATE_OPEN) ? " OPEN":"CLOSE"), - mac_table[i].requested_credit); -#ifdef PROP_TXSTATUS_DEBUG - bcm_bprintf(strbuf, "MAC_table[%d]: (opened, closed) = (%d, %d)\n", - i, mac_table[i].opened_ct, mac_table[i].closed_ct); -#endif - bcm_bprintf(strbuf, "MAC_table[%d].DELAYQ" - "(sup,ac0),(sup,ac1),(sup,ac2),(sup,ac3) = " - "(%d,%d),(%d,%d),(%d,%d),(%d,%d)\n", - i, - mac_table[i].psq.q[0].len, - mac_table[i].psq.q[1].len, - mac_table[i].psq.q[2].len, - mac_table[i].psq.q[3].len, - mac_table[i].psq.q[4].len, - mac_table[i].psq.q[5].len, - mac_table[i].psq.q[6].len, - mac_table[i].psq.q[7].len); - } - } - -#ifdef PROP_TXSTATUS_DEBUG - { - int avg; - int moving_avg = 0; - int moving_samples; - - if (wlfc->stats.latency_sample_count) { - moving_samples = sizeof(wlfc->stats.deltas)/sizeof(uint32); - - for (i = 0; i < moving_samples; i++) - moving_avg += wlfc->stats.deltas[i]; - moving_avg /= moving_samples; - - avg = (100 * wlfc->stats.total_status_latency) / - wlfc->stats.latency_sample_count; - bcm_bprintf(strbuf, "txstatus latency (average, last, moving[%d]) = " - "(%d.%d, %03d, %03d)\n", - moving_samples, avg/100, (avg - (avg/100)*100), - wlfc->stats.latency_most_recent, - moving_avg); - } - } - - bcm_bprintf(strbuf, "wlfc- fifo[0-5] credit stats: sent = (%d,%d,%d,%d,%d,%d), " - "back = (%d,%d,%d,%d,%d,%d)\n", - wlfc->stats.fifo_credits_sent[0], - wlfc->stats.fifo_credits_sent[1], - wlfc->stats.fifo_credits_sent[2], - wlfc->stats.fifo_credits_sent[3], - wlfc->stats.fifo_credits_sent[4], - wlfc->stats.fifo_credits_sent[5], - - wlfc->stats.fifo_credits_back[0], - wlfc->stats.fifo_credits_back[1], - wlfc->stats.fifo_credits_back[2], - wlfc->stats.fifo_credits_back[3], - wlfc->stats.fifo_credits_back[4], - wlfc->stats.fifo_credits_back[5]); - { - uint32 fifo_cr_sent = 0; - uint32 fifo_cr_acked = 0; - uint32 request_cr_sent = 0; - uint32 request_cr_ack = 0; - uint32 bc_mc_cr_ack = 0; - - for (i = 0; i < sizeof(wlfc->stats.fifo_credits_sent)/sizeof(uint32); i++) { - fifo_cr_sent += wlfc->stats.fifo_credits_sent[i]; - } - - for (i = 0; i < sizeof(wlfc->stats.fifo_credits_back)/sizeof(uint32); i++) { - fifo_cr_acked += wlfc->stats.fifo_credits_back[i]; - } - - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (wlfc->destination_entries.nodes[i].occupied) { - request_cr_sent += - wlfc->destination_entries.nodes[i].dstncredit_sent_packets; - } - } - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - if (wlfc->destination_entries.interfaces[i].occupied) { - request_cr_sent += - wlfc->destination_entries.interfaces[i].dstncredit_sent_packets; - } - } - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (wlfc->destination_entries.nodes[i].occupied) { - request_cr_ack += - wlfc->destination_entries.nodes[i].dstncredit_acks; - } - } - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - if (wlfc->destination_entries.interfaces[i].occupied) { - request_cr_ack += - wlfc->destination_entries.interfaces[i].dstncredit_acks; - } - } - bcm_bprintf(strbuf, "wlfc- (sent, status) => pq(%d,%d), vq(%d,%d)," - "other:%d, bc_mc:%d, signal-only, (sent,freed): (%d,%d)", - fifo_cr_sent, fifo_cr_acked, - request_cr_sent, request_cr_ack, - wlfc->destination_entries.other.dstncredit_acks, - bc_mc_cr_ack, - wlfc->stats.signal_only_pkts_sent, wlfc->stats.signal_only_pkts_freed); - } -#endif /* PROP_TXSTATUS_DEBUG */ - bcm_bprintf(strbuf, "\n"); - bcm_bprintf(strbuf, "wlfc- pkt((in,2bus,txstats,hdrpull),(dropped,hdr_only,wlc_tossed)" - "(freed,free_err,rollback)) = " - "((%d,%d,%d,%d),(%d,%d,%d),(%d,%d,%d))\n", - wlfc->stats.pktin, - wlfc->stats.pkt2bus, - wlfc->stats.txstatus_in, - wlfc->stats.dhd_hdrpulls, - - wlfc->stats.pktdropped, - wlfc->stats.wlfc_header_only_pkt, - wlfc->stats.wlc_tossed_pkts, - - wlfc->stats.pkt_freed, - wlfc->stats.pkt_free_err, wlfc->stats.rollback); - - bcm_bprintf(strbuf, "wlfc- suppress((d11,wlc,err),enq(d11,wl,hq,mac?),retx(d11,wlc,hq)) = " - "((%d,%d,%d),(%d,%d,%d,%d),(%d,%d,%d))\n", - - wlfc->stats.d11_suppress, - wlfc->stats.wl_suppress, - wlfc->stats.bad_suppress, - - wlfc->stats.psq_d11sup_enq, - wlfc->stats.psq_wlsup_enq, - wlfc->stats.psq_hostq_enq, - wlfc->stats.mac_handle_notfound, - - wlfc->stats.psq_d11sup_retx, - wlfc->stats.psq_wlsup_retx, - wlfc->stats.psq_hostq_retx); - return; -} - -/* Create a place to store all packet pointers submitted to the firmware until - a status comes back, suppress or otherwise. - - hang-er: noun, a contrivance on which things are hung, as a hook. -*/ -static void* -dhd_wlfc_hanger_create(osl_t *osh, int max_items) -{ - int i; - wlfc_hanger_t* hanger; - - /* allow only up to a specific size for now */ - ASSERT(max_items == WLFC_HANGER_MAXITEMS); - - if ((hanger = (wlfc_hanger_t*)MALLOC(osh, WLFC_HANGER_SIZE(max_items))) == NULL) - return NULL; - - memset(hanger, 0, WLFC_HANGER_SIZE(max_items)); - hanger->max_items = max_items; - - for (i = 0; i < hanger->max_items; i++) { - hanger->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - } - return hanger; -} - -static int -dhd_wlfc_hanger_delete(osl_t *osh, void* hanger) -{ - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - if (h) { - MFREE(osh, h, WLFC_HANGER_SIZE(h->max_items)); - return BCME_OK; - } - return BCME_BADARG; -} - -static uint16 -dhd_wlfc_hanger_get_free_slot(void* hanger) -{ - int i; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - if (h) { - for (i = 0; i < h->max_items; i++) { - if (h->items[i].state == WLFC_HANGER_ITEM_STATE_FREE) - return (uint16)i; - } - h->failed_slotfind++; - } - return WLFC_HANGER_MAXITEMS; -} - -static int -dhd_wlfc_hanger_get_genbit(void* hanger, void* pkt, uint32 slot_id, int* gen) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - *gen = 0xff; - - /* this packet was not pushed at the time it went to the firmware */ - if (slot_id == WLFC_HANGER_MAXITEMS) - return BCME_NOTFOUND; - - if (h) { - if ((h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) || - (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED)) { - *gen = h->items[slot_id].gen; - } - else { - rc = BCME_NOTFOUND; - } - } - else - rc = BCME_BADARG; - return rc; -} - -static int -dhd_wlfc_hanger_pushpkt(void* hanger, void* pkt, uint32 slot_id) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - if (h && (slot_id < WLFC_HANGER_MAXITEMS)) { - if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_FREE) { - h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE; - h->items[slot_id].pkt = pkt; - h->items[slot_id].identifier = slot_id; - h->pushed++; - } - else { - h->failed_to_push++; - rc = BCME_NOTFOUND; - } - } - else - rc = BCME_BADARG; - return rc; -} - -static int -dhd_wlfc_hanger_poppkt(void* hanger, uint32 slot_id, void** pktout, int remove_from_hanger) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - /* this packet was not pushed at the time it went to the firmware */ - if (slot_id == WLFC_HANGER_MAXITEMS) - return BCME_NOTFOUND; - - if (h) { - if (h->items[slot_id].state != WLFC_HANGER_ITEM_STATE_FREE) { - *pktout = h->items[slot_id].pkt; - if (remove_from_hanger) { - h->items[slot_id].state = - WLFC_HANGER_ITEM_STATE_FREE; - h->items[slot_id].pkt = NULL; - h->items[slot_id].identifier = 0; - h->items[slot_id].gen = 0xff; - h->popped++; - } - } - else { - h->failed_to_pop++; - rc = BCME_NOTFOUND; - } - } - else - rc = BCME_BADARG; - return rc; -} - -static int -dhd_wlfc_hanger_mark_suppressed(void* hanger, uint32 slot_id, uint8 gen) -{ - int rc = BCME_OK; - wlfc_hanger_t* h = (wlfc_hanger_t*)hanger; - - /* this packet was not pushed at the time it went to the firmware */ - if (slot_id == WLFC_HANGER_MAXITEMS) - return BCME_NOTFOUND; - if (h) { - h->items[slot_id].gen = gen; - if (h->items[slot_id].state == WLFC_HANGER_ITEM_STATE_INUSE) { - h->items[slot_id].state = WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED; - } - else - rc = BCME_BADARG; - } - else - rc = BCME_BADARG; - - return rc; -} - -static int -_dhd_wlfc_pushheader(athost_wl_status_info_t* ctx, void* p, bool tim_signal, - uint8 tim_bmp, uint8 mac_handle, uint32 htodtag) -{ - uint32 wl_pktinfo = 0; - uint8* wlh; - uint8 dataOffset; - uint8 fillers; - uint8 tim_signal_len = 0; - - struct bdc_header *h; - - if (tim_signal) { - tim_signal_len = 1 + 1 + WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; - } - - /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ - dataOffset = WLFC_CTL_VALUE_LEN_PKTTAG + 2 + tim_signal_len; - fillers = ROUNDUP(dataOffset, 4) - dataOffset; - dataOffset += fillers; - - PKTPUSH(ctx->osh, p, dataOffset); - wlh = (uint8*) PKTDATA(ctx->osh, p); - - wl_pktinfo = htol32(htodtag); - - wlh[0] = WLFC_CTL_TYPE_PKTTAG; - wlh[1] = WLFC_CTL_VALUE_LEN_PKTTAG; - memcpy(&wlh[2], &wl_pktinfo, sizeof(uint32)); - - if (tim_signal_len) { - wlh[dataOffset - fillers - tim_signal_len ] = - WLFC_CTL_TYPE_PENDING_TRAFFIC_BMP; - wlh[dataOffset - fillers - tim_signal_len + 1] = - WLFC_CTL_VALUE_LEN_PENDING_TRAFFIC_BMP; - wlh[dataOffset - fillers - tim_signal_len + 2] = mac_handle; - wlh[dataOffset - fillers - tim_signal_len + 3] = tim_bmp; - } - if (fillers) - memset(&wlh[dataOffset - fillers], WLFC_CTL_TYPE_FILLER, fillers); - - PKTPUSH(ctx->osh, p, BDC_HEADER_LEN); - h = (struct bdc_header *)PKTDATA(ctx->osh, p); - h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); - if (PKTSUMNEEDED(p)) - h->flags |= BDC_FLAG_SUM_NEEDED; - - - h->priority = (PKTPRIO(p) & BDC_PRIORITY_MASK); - h->flags2 = 0; - h->dataOffset = dataOffset >> 2; - BDC_SET_IF_IDX(h, DHD_PKTTAG_IF(PKTTAG(p))); - return BCME_OK; -} - -static int -_dhd_wlfc_pullheader(athost_wl_status_info_t* ctx, void* pktbuf) -{ - struct bdc_header *h; - - if (PKTLEN(ctx->osh, pktbuf) < BDC_HEADER_LEN) { - WLFC_DBGMESG(("%s: rx data too short (%d < %d)\n", __FUNCTION__, - PKTLEN(ctx->osh, pktbuf), BDC_HEADER_LEN)); - return BCME_ERROR; - } - h = (struct bdc_header *)PKTDATA(ctx->osh, pktbuf); - - /* pull BDC header */ - PKTPULL(ctx->osh, pktbuf, BDC_HEADER_LEN); - /* pull wl-header */ - PKTPULL(ctx->osh, pktbuf, (h->dataOffset << 2)); - return BCME_OK; -} - -static wlfc_mac_descriptor_t* -_dhd_wlfc_find_table_entry(athost_wl_status_info_t* ctx, void* p) -{ - int i; - wlfc_mac_descriptor_t* table = ctx->destination_entries.nodes; - uint8 ifid = DHD_PKTTAG_IF(PKTTAG(p)); - uint8* dstn = DHD_PKTTAG_DSTN(PKTTAG(p)); - - /* no lookup necessary, only if this packet belongs to STA interface */ - if (((ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_STA) || - ETHER_ISMULTI(dstn) || - (ctx->destination_entries.interfaces[ifid].iftype == WLC_E_IF_ROLE_P2P_CLIENT)) && - (ctx->destination_entries.interfaces[ifid].occupied)) { - return &ctx->destination_entries.interfaces[ifid]; - } - - for (i = 0; i < WLFC_MAC_DESC_TABLE_SIZE; i++) { - if (table[i].occupied) { - if (table[i].interface_id == ifid) { - if (!memcmp(table[i].ea, dstn, ETHER_ADDR_LEN)) - return &table[i]; - } - } - } - return &ctx->destination_entries.other; -} - -static int -_dhd_wlfc_rollback_packet_toq(athost_wl_status_info_t* ctx, - void* p, ewlfc_packet_state_t pkt_type, uint32 hslot) -{ - /* - put the packet back to the head of queue - - - a packet from send-q will need to go back to send-q and not delay-q - since that will change the order of packets. - - suppressed packet goes back to suppress sub-queue - - pull out the header, if new or delayed packet - - Note: hslot is used only when header removal is done. - */ - wlfc_mac_descriptor_t* entry; - void* pktout; - int rc = BCME_OK; - int prec; - - entry = _dhd_wlfc_find_table_entry(ctx, p); - prec = DHD_PKTTAG_FIFO(PKTTAG(p)); - if (entry != NULL) { - if (pkt_type == eWLFC_PKTTYPE_SUPPRESSED) { - /* wl-header is saved for suppressed packets */ - if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, ((prec << 1) + 1), p) == NULL) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - rc = BCME_ERROR; - } - } - else { - /* remove header first */ - _dhd_wlfc_pullheader(ctx, p); - - if (pkt_type == eWLFC_PKTTYPE_DELAYED) { - /* delay-q packets are going to delay-q */ - if (WLFC_PKTQ_PENQ_HEAD(&entry->psq, (prec << 1), p) == NULL) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - rc = BCME_ERROR; - } - } - else { - /* these are going to SENDQ */ - if (WLFC_PKTQ_PENQ_HEAD(&ctx->SENDQ, prec, p) == NULL) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - rc = BCME_ERROR; - } - } - /* free the hanger slot */ - dhd_wlfc_hanger_poppkt(ctx->hanger, hslot, &pktout, 1); - - /* decrement sequence count */ - WLFC_DECR_SEQCOUNT(entry, prec); - } - /* - if this packet did not count against FIFO credit, it must have - taken a requested_credit from the firmware (for pspoll etc.) - */ - if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { - entry->requested_credit++; - } - } - else { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - rc = BCME_ERROR; - } - if (rc != BCME_OK) - ctx->stats.rollback_failed++; - else - ctx->stats.rollback++; - - return rc; -} - -static void -_dhd_wlfc_flow_control_check(athost_wl_status_info_t* ctx, struct pktq* pq, uint8 if_id) -{ - if ((pq->len <= WLFC_FLOWCONTROL_LOWATER) && (ctx->hostif_flow_state[if_id] == ON)) { - /* start traffic */ - ctx->hostif_flow_state[if_id] = OFF; - /* - WLFC_DBGMESG(("qlen:%02d, if:%02d, ->OFF, start traffic %s()\n", - pq->len, if_id, __FUNCTION__)); - */ - WLFC_DBGMESG(("F")); -#ifndef BCMDBUS - dhd_txflowcontrol(ctx->dhdp, if_id, OFF); -#endif - ctx->toggle_host_if = 0; - } - if ((pq->len >= WLFC_FLOWCONTROL_HIWATER) && (ctx->hostif_flow_state[if_id] == OFF)) { - /* stop traffic */ - ctx->hostif_flow_state[if_id] = ON; - /* - WLFC_DBGMESG(("qlen:%02d, if:%02d, ->ON, stop traffic %s()\n", - pq->len, if_id, __FUNCTION__)); - */ - WLFC_DBGMESG(("N")); - /* XXX: debug in progress */ -#ifndef BCMDBUS - dhd_txflowcontrol(ctx->dhdp, if_id, ON); -#endif - ctx->host_ifidx = if_id; - ctx->toggle_host_if = 1; - } - return; -} - -static int -_dhd_wlfc_send_signalonly_packet(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, - uint8 ta_bmp) -{ - int rc = BCME_OK; - void* p = NULL; - int dummylen = ((dhd_pub_t *)ctx->dhdp)->hdrlen+ 12; - - /* allocate a dummy packet */ - p = PKTGET(ctx->osh, dummylen, TRUE); - if (p) { - PKTPULL(ctx->osh, p, dummylen); - DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), 0); - _dhd_wlfc_pushheader(ctx, p, TRUE, ta_bmp, entry->mac_handle, 0); - DHD_PKTTAG_SETSIGNALONLY(PKTTAG(p), 1); -#ifdef PROP_TXSTATUS_DEBUG - ctx->stats.signal_only_pkts_sent++; -#endif - rc = dhd_bus_txdata(((dhd_pub_t *)ctx->dhdp)->bus, p); - if (rc != BCME_OK) { - PKTFREE(ctx->osh, p, TRUE); - } - } - else { - DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", - __FUNCTION__, dummylen)); - rc = BCME_NOMEM; - } - return rc; -} - -/* Return TRUE if traffic availability changed */ -static bool -_dhd_wlfc_traffic_pending_check(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, - int prec) -{ - bool rc = FALSE; - - if (entry->state == WLFC_STATE_CLOSE) { - if ((pktq_plen(&entry->psq, (prec << 1)) == 0) && - (pktq_plen(&entry->psq, ((prec << 1) + 1)) == 0)) { - - if (entry->traffic_pending_bmp & NBITVAL(prec)) { - rc = TRUE; - entry->traffic_pending_bmp = - entry->traffic_pending_bmp & ~ NBITVAL(prec); - } - } - else { - if (!(entry->traffic_pending_bmp & NBITVAL(prec))) { - rc = TRUE; - entry->traffic_pending_bmp = - entry->traffic_pending_bmp | NBITVAL(prec); - } - } - } - if (rc) { - /* request a TIM update to firmware at the next piggyback opportunity */ - if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp) { - entry->send_tim_signal = 1; - _dhd_wlfc_send_signalonly_packet(ctx, entry, entry->traffic_pending_bmp); - entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; - entry->send_tim_signal = 0; - } - else { - rc = FALSE; - } - } - return rc; -} - -static int -_dhd_wlfc_enque_suppressed(athost_wl_status_info_t* ctx, int prec, void* p) -{ - wlfc_mac_descriptor_t* entry; - - entry = _dhd_wlfc_find_table_entry(ctx, p); - if (entry == NULL) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_NOTFOUND; - } - /* - - suppressed packets go to sub_queue[2*prec + 1] AND - - delayed packets go to sub_queue[2*prec + 0] to ensure - order of delivery. - */ - if (WLFC_PKTQ_PENQ(&entry->psq, ((prec << 1) + 1), p) == NULL) { - ctx->stats.delayq_full_error++; - /* WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); */ - WLFC_DBGMESG(("s")); - return BCME_ERROR; - } - /* A packet has been pushed, update traffic availability bitmap, if applicable */ - _dhd_wlfc_traffic_pending_check(ctx, entry, prec); - _dhd_wlfc_flow_control_check(ctx, &entry->psq, DHD_PKTTAG_IF(PKTTAG(p))); - return BCME_OK; -} - -static int -_dhd_wlfc_pretx_pktprocess(athost_wl_status_info_t* ctx, - wlfc_mac_descriptor_t* entry, void* p, int header_needed, uint32* slot) -{ - int rc = BCME_OK; - int hslot = WLFC_HANGER_MAXITEMS; - bool send_tim_update = FALSE; - uint32 htod = 0; - uint8 free_ctr; - - *slot = hslot; - - if (entry == NULL) { - entry = _dhd_wlfc_find_table_entry(ctx, p); - } - - if (entry == NULL) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_ERROR; - } - if (entry->send_tim_signal) { - send_tim_update = TRUE; - entry->send_tim_signal = 0; - entry->traffic_lastreported_bmp = entry->traffic_pending_bmp; - } - if (header_needed) { - hslot = dhd_wlfc_hanger_get_free_slot(ctx->hanger); - free_ctr = WLFC_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); - DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); - WLFC_PKTFLAG_SET_GENERATION(htod, entry->generation); - entry->transit_count++; - } - else { - hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - } - WLFC_PKTID_HSLOT_SET(htod, hslot); - WLFC_PKTID_FREERUNCTR_SET(htod, free_ctr); - DHD_PKTTAG_SETPKTDIR(PKTTAG(p), 1); - WL_TXSTATUS_SET_FLAGS(htod, WLFC_PKTFLAG_PKTFROMHOST); - WL_TXSTATUS_SET_FIFO(htod, DHD_PKTTAG_FIFO(PKTTAG(p))); - - - if (!DHD_PKTTAG_CREDITCHECK(PKTTAG(p))) { - /* - Indicate that this packet is being sent in response to an - explicit request from the firmware side. - */ - WLFC_PKTFLAG_SET_PKTREQUESTED(htod); - } - else { - WLFC_PKTFLAG_CLR_PKTREQUESTED(htod); - } - if (header_needed) { - rc = _dhd_wlfc_pushheader(ctx, p, send_tim_update, - entry->traffic_lastreported_bmp, entry->mac_handle, htod); - if (rc == BCME_OK) { - DHD_PKTTAG_SET_H2DTAG(PKTTAG(p), htod); - /* - a new header was created for this packet. - push to hanger slot and scrub q. Since bus - send succeeded, increment seq number as well. - */ - rc = dhd_wlfc_hanger_pushpkt(ctx->hanger, p, hslot); - if (rc == BCME_OK) { - /* increment free running sequence count */ - WLFC_INCR_SEQCOUNT(entry, DHD_PKTTAG_FIFO(PKTTAG(p))); -#ifdef PROP_TXSTATUS_DEBUG - ((wlfc_hanger_t*)(ctx->hanger))->items[hslot].push_time = - OSL_SYSUPTIME(); -#endif - } - else { - WLFC_DBGMESG(("%s() hanger_pushpkt() failed, rc: %d\n", - __FUNCTION__, rc)); - } - } - } - else { - int gen; - - /* remove old header */ - _dhd_wlfc_pullheader(ctx, p); - - hslot = WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - dhd_wlfc_hanger_get_genbit(ctx->hanger, p, hslot, &gen); - - WLFC_PKTFLAG_SET_GENERATION(htod, gen); - free_ctr = WLFC_PKTID_FREERUNCTR_GET(DHD_PKTTAG_H2DTAG(PKTTAG(p))); - /* push new header */ - _dhd_wlfc_pushheader(ctx, p, send_tim_update, - entry->traffic_lastreported_bmp, entry->mac_handle, htod); - } - *slot = hslot; - return rc; -} - -static int -_dhd_wlfc_is_destination_closed(athost_wl_status_info_t* ctx, - wlfc_mac_descriptor_t* entry, int prec) -{ - if (ctx->destination_entries.interfaces[entry->interface_id].iftype == - WLC_E_IF_ROLE_P2P_GO) { - /* - destination interface is of type p2p GO. - For a p2pGO interface, if the destination is OPEN but the interface is - CLOSEd, do not send traffic. But if the dstn is CLOSEd while there is - destination-specific-credit left send packets. This is because the - firmware storing the destination-specific-requested packet in queue. - */ - if ((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && - (entry->requested_packet == 0)) - return 1; - } - /* AP, p2p_go -> unicast desc entry, STA/p2p_cl -> interface desc. entry */ - if (((entry->state == WLFC_STATE_CLOSE) && (entry->requested_credit == 0) && - (entry->requested_packet == 0)) || - (!(entry->ac_bitmap & (1 << prec)))) - return 1; - - return 0; -} - -static void* -_dhd_wlfc_deque_delayedq(athost_wl_status_info_t* ctx, - int prec, uint8* ac_credit_spent, uint8* needs_hdr, wlfc_mac_descriptor_t** entry_out) -{ - wlfc_mac_descriptor_t* entry; - wlfc_mac_descriptor_t* table; - uint8 token_pos; - int total_entries; - void* p = NULL; - int pout; - int i; - - *entry_out = NULL; - token_pos = ctx->token_pos[prec]; - /* most cases a packet will count against FIFO credit */ - *ac_credit_spent = 1; - *needs_hdr = 1; - - /* search all entries, include nodes as well as interfaces */ - table = (wlfc_mac_descriptor_t*)&ctx->destination_entries; - total_entries = sizeof(ctx->destination_entries)/sizeof(wlfc_mac_descriptor_t); - - for (i = 0; i < total_entries; i++) { - entry = &table[(token_pos + i) % total_entries]; - if (entry->occupied) { - if (!_dhd_wlfc_is_destination_closed(ctx, entry, prec)) { - p = pktq_mdeq(&entry->psq, - /* higher precedence will be picked up first, - i.e. suppressed packets before delayed ones - */ - NBITVAL((prec << 1) + 1), &pout); - *needs_hdr = 0; - - if (p == NULL) { - if (entry->suppressed == TRUE) { - if ((entry->suppr_transit_count <= - entry->suppress_count)) { - entry->suppressed = FALSE; - } else { - return NULL; - } - } - /* De-Q from delay Q */ - p = pktq_mdeq(&entry->psq, - NBITVAL((prec << 1)), - &pout); - *needs_hdr = 1; - } - - if (p != NULL) { - /* did the packet come from suppress sub-queue? */ - if (entry->requested_credit > 0) { - entry->requested_credit--; -#ifdef PROP_TXSTATUS_DEBUG - entry->dstncredit_sent_packets++; -#endif - /* - if the packet was pulled out while destination is in - closed state but had a non-zero packets requested, - then this should not count against the FIFO credit. - That is due to the fact that the firmware will - most likely hold onto this packet until a suitable - time later to push it to the appropriate AC FIFO. - */ - if (entry->state == WLFC_STATE_CLOSE) - *ac_credit_spent = 0; - } - else if (entry->requested_packet > 0) { - entry->requested_packet--; - DHD_PKTTAG_SETONETIMEPKTRQST(PKTTAG(p)); - if (entry->state == WLFC_STATE_CLOSE) - *ac_credit_spent = 0; - } - /* move token to ensure fair round-robin */ - ctx->token_pos[prec] = - (token_pos + i + 1) % total_entries; - *entry_out = entry; - _dhd_wlfc_flow_control_check(ctx, &entry->psq, - DHD_PKTTAG_IF(PKTTAG(p))); - /* - A packet has been picked up, update traffic - availability bitmap, if applicable - */ - _dhd_wlfc_traffic_pending_check(ctx, entry, prec); - return p; - } - } - } - } - return NULL; -} - -static void* -_dhd_wlfc_deque_sendq(athost_wl_status_info_t* ctx, int prec) -{ - wlfc_mac_descriptor_t* entry; - void* p; - - - p = pktq_pdeq(&ctx->SENDQ, prec); - if (p != NULL) { - if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p)))) - /* bc/mc packets do not have a delay queue */ - return p; - - entry = _dhd_wlfc_find_table_entry(ctx, p); - - if (entry == NULL) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return p; - } - - while ((p != NULL)) { - /* - - suppressed packets go to sub_queue[2*prec + 1] AND - - delayed packets go to sub_queue[2*prec + 0] to ensure - order of delivery. - */ - if (WLFC_PKTQ_PENQ(&entry->psq, (prec << 1), p) == NULL) { - WLFC_DBGMESG(("D")); - /* dhd_txcomplete(ctx->dhdp, p, FALSE); */ - PKTFREE(ctx->osh, p, TRUE); - ctx->stats.delayq_full_error++; - } - /* - A packet has been pushed, update traffic availability bitmap, - if applicable - */ - _dhd_wlfc_traffic_pending_check(ctx, entry, prec); - - p = pktq_pdeq(&ctx->SENDQ, prec); - if (p == NULL) - break; - - entry = _dhd_wlfc_find_table_entry(ctx, p); - - if ((entry == NULL) || (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(p))))) { - return p; - } - } - } - return p; -} - -static int -_dhd_wlfc_mac_entry_update(athost_wl_status_info_t* ctx, wlfc_mac_descriptor_t* entry, - ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) -{ - int rc = BCME_OK; - - if (action == eWLFC_MAC_ENTRY_ACTION_ADD) { - entry->occupied = 1; - entry->state = WLFC_STATE_OPEN; - entry->requested_credit = 0; - entry->interface_id = ifid; - entry->iftype = iftype; - entry->ac_bitmap = 0xff; /* update this when handling APSD */ - /* for an interface entry we may not care about the MAC address */ - if (ea != NULL) - memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); - pktq_init(&entry->psq, WLFC_PSQ_PREC_COUNT, WLFC_PSQ_LEN); - } - else if (action == eWLFC_MAC_ENTRY_ACTION_UPDATE) { - entry->occupied = 1; - entry->state = WLFC_STATE_OPEN; - entry->requested_credit = 0; - entry->interface_id = ifid; - entry->iftype = iftype; - entry->ac_bitmap = 0xff; /* update this when handling APSD */ - /* for an interface entry we may not care about the MAC address */ - if (ea != NULL) - memcpy(&entry->ea[0], ea, ETHER_ADDR_LEN); - } - - else if (action == eWLFC_MAC_ENTRY_ACTION_DEL) { - entry->occupied = 0; - entry->state = WLFC_STATE_CLOSE; - entry->requested_credit = 0; - /* enable after packets are queued-deqeued properly. - pktq_flush(dhd->osh, &entry->psq, FALSE, NULL, 0); - */ - } - return rc; -} - -int -_dhd_wlfc_borrow_credit(athost_wl_status_info_t* ctx, uint8 available_credit_map, int borrower_ac) -{ - int lender_ac; - int rc = BCME_ERROR; - - if (ctx == NULL || available_credit_map == 0) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - /* Borrow from lowest priority available AC (including BC/MC credits) */ - for (lender_ac = 0; lender_ac <= AC_COUNT; lender_ac++) { - if ((available_credit_map && (1 << lender_ac)) && - (ctx->FIFO_credit[lender_ac] > 0)) { - ctx->credits_borrowed[borrower_ac][lender_ac]++; - ctx->FIFO_credit[lender_ac]--; - rc = BCME_OK; - break; - } - } - - return rc; -} - -int -dhd_wlfc_interface_entry_update(void* state, - ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) -{ - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - wlfc_mac_descriptor_t* entry; - - if (ifid >= WLFC_MAX_IFNUM) - return BCME_BADARG; - - entry = &ctx->destination_entries.interfaces[ifid]; - return _dhd_wlfc_mac_entry_update(ctx, entry, action, ifid, iftype, ea); -} - -int -dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits) -{ - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - - /* update the AC FIFO credit map */ - ctx->FIFO_credit[0] = credits[0]; - ctx->FIFO_credit[1] = credits[1]; - ctx->FIFO_credit[2] = credits[2]; - ctx->FIFO_credit[3] = credits[3]; - /* credit for bc/mc packets */ - ctx->FIFO_credit[4] = credits[4]; - /* credit for ATIM FIFO is not used yet. */ - ctx->FIFO_credit[5] = 0; - return BCME_OK; -} - -int -dhd_wlfc_enque_sendq(void* state, int prec, void* p) -{ - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - - if ((state == NULL) || - /* prec = AC_COUNT is used for bc/mc queue */ - (prec > AC_COUNT) || - (p == NULL)) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - if (FALSE == dhd_prec_enq(ctx->dhdp, &ctx->SENDQ, p, prec)) { - ctx->stats.sendq_full_error++; - /* - WLFC_DBGMESG(("Error: %s():%d, qlen:%d\n", - __FUNCTION__, __LINE__, ctx->SENDQ.len)); - */ - WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, prec); - WLFC_DBGMESG(("Q")); - PKTFREE(ctx->osh, p, TRUE); - return BCME_ERROR; - } - ctx->stats.pktin++; - /* _dhd_wlfc_flow_control_check(ctx, &ctx->SENDQ, DHD_PKTTAG_IF(PKTTAG(p))); */ - return BCME_OK; -} - -int -_dhd_wlfc_handle_packet_commit(athost_wl_status_info_t* ctx, int ac, - dhd_wlfc_commit_info_t *commit_info, f_commitpkt_t fcommit, void* commit_ctx) -{ - uint32 hslot; - int rc; - - /* - if ac_fifo_credit_spent = 0 - - This packet will not count against the FIFO credit. - To ensure the txstatus corresponding to this packet - does not provide an implied credit (default behavior) - mark the packet accordingly. - - if ac_fifo_credit_spent = 1 - - This is a normal packet and it counts against the FIFO - credit count. - */ - DHD_PKTTAG_SETCREDITCHECK(PKTTAG(commit_info->p), commit_info->ac_fifo_credit_spent); - rc = _dhd_wlfc_pretx_pktprocess(ctx, commit_info->mac_entry, commit_info->p, - commit_info->needs_hdr, &hslot); - - if (rc == BCME_OK) - rc = fcommit(commit_ctx, commit_info->p); - else - ctx->stats.generic_error++; - - if (rc == BCME_OK) { - ctx->stats.pkt2bus++; - if (commit_info->ac_fifo_credit_spent) { - ctx->stats.sendq_pkts[ac]++; - WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac); - } - } - else { - /* - bus commit has failed, rollback. - - remove wl-header for a delayed packet - - save wl-header header for suppressed packets - */ - rc = _dhd_wlfc_rollback_packet_toq(ctx, commit_info->p, - (commit_info->pkt_type), hslot); - if (rc != BCME_OK) - ctx->stats.rollback_failed++; - - rc = BCME_ERROR; - } - - return rc; -} - -int -dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx) -{ - int ac; - int credit; - int rc; - dhd_wlfc_commit_info_t commit_info; - athost_wl_status_info_t* ctx = (athost_wl_status_info_t*)state; - int credit_count = 0; - int bus_retry_count = 0; - uint8 ac_available = 0; /* Bitmask for 4 ACs + BC/MC */ - - if ((state == NULL) || - (fcommit == NULL)) { - WLFC_DBGMESG(("Error: %s():%d\n", __FUNCTION__, __LINE__)); - return BCME_BADARG; - } - - memset(&commit_info, 0, sizeof(commit_info)); - - /* - Commit packets for regular AC traffic. Higher priority first. - First, use up FIFO credits available to each AC. Based on distribution - and credits left, borrow from other ACs as applicable - - -NOTE: - If the bus between the host and firmware is overwhelmed by the - traffic from host, it is possible that higher priority traffic - starves the lower priority queue. If that occurs often, we may - have to employ weighted round-robin or ucode scheme to avoid - low priority packet starvation. - */ - - for (ac = AC_COUNT; ac >= 0; ac--) { - - int initial_credit_count = ctx->FIFO_credit[ac]; - - /* packets from SENDQ are fresh and they'd need header and have no MAC entry */ - commit_info.needs_hdr = 1; - commit_info.mac_entry = NULL; - commit_info.pkt_type = eWLFC_PKTTYPE_NEW; - - do { - commit_info.p = _dhd_wlfc_deque_sendq(ctx, ac); - if (commit_info.p == NULL) - break; - else if (ETHER_ISMULTI(DHD_PKTTAG_DSTN(PKTTAG(commit_info.p)))) { - ASSERT(ac == AC_COUNT); - - if (ctx->FIFO_credit[ac]) { - rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, - fcommit, commit_ctx); - - /* Bus commits may fail (e.g. flow control); abort after retries */ - if (rc == BCME_OK) { - if (commit_info.ac_fifo_credit_spent) { - (void) _dhd_wlfc_borrow_credit(ctx, - ac_available, ac); - credit_count--; - } - } else { - bus_retry_count++; - if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR((" %s: bus error\n", - __FUNCTION__)); - return rc; - } - } - } - } - - } while (commit_info.p); - - for (credit = 0; credit < ctx->FIFO_credit[ac];) { - commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, - &(commit_info.ac_fifo_credit_spent), - &(commit_info.needs_hdr), - &(commit_info.mac_entry)); - - if (commit_info.p == NULL) - break; - - commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : - eWLFC_PKTTYPE_SUPPRESSED; - - rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, - fcommit, commit_ctx); - - /* Bus commits may fail (e.g. flow control); abort after retries */ - if (rc == BCME_OK) { - if (commit_info.ac_fifo_credit_spent) { - credit++; - } - } - else { - bus_retry_count++; - if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n")); - ctx->FIFO_credit[ac] -= credit; - return rc; - } - } - } - ctx->FIFO_credit[ac] -= credit; - - - /* If no credits were used, the queue is idle and can be re-used - Note that resv credits cannot be borrowed - */ - if (initial_credit_count == ctx->FIFO_credit[ac]) { - ac_available |= (1 << ac); - credit_count += ctx->FIFO_credit[ac]; - } - } - - /* We borrow only for AC_BE and only if no other traffic seen for DEFER_PERIOD - - Note that (ac_available & WLFC_AC_BE_TRAFFIC_ONLY) is done to: - a) ignore BC/MC for deferring borrow - b) ignore AC_BE being available along with other ACs - (this should happen only for pure BC/MC traffic) - - i.e. AC_VI, AC_VO, AC_BK all MUST be available (i.e. no traffic) and - we do not care if AC_BE and BC/MC are available or not - */ - if ((ac_available & WLFC_AC_BE_TRAFFIC_ONLY) == WLFC_AC_BE_TRAFFIC_ONLY) { - - if (ctx->allow_credit_borrow) { - ac = 1; /* Set ac to AC_BE and borrow credits */ - } - else { - int delta; - int curr_t = OSL_SYSUPTIME(); - - if (curr_t > ctx->borrow_defer_timestamp) - delta = curr_t - ctx->borrow_defer_timestamp; - else - delta = 0xffffffff + curr_t - ctx->borrow_defer_timestamp; - - if (delta >= WLFC_BORROW_DEFER_PERIOD_MS) { - /* Reset borrow but defer to next iteration (defensive borrowing) */ - ctx->allow_credit_borrow = TRUE; - ctx->borrow_defer_timestamp = 0; - } - return BCME_OK; - } - } - else { - /* If we have multiple AC traffic, turn off borrowing, mark time and bail out */ - ctx->allow_credit_borrow = FALSE; - ctx->borrow_defer_timestamp = OSL_SYSUPTIME(); - return BCME_OK; - } - - /* At this point, borrow all credits only for "ac" (which should be set above to AC_BE) - Generically use "ac" only in case we extend to all ACs in future - */ - for (; (credit_count > 0);) { - - commit_info.p = _dhd_wlfc_deque_delayedq(ctx, ac, - &(commit_info.ac_fifo_credit_spent), - &(commit_info.needs_hdr), - &(commit_info.mac_entry)); - if (commit_info.p == NULL) - break; - - commit_info.pkt_type = (commit_info.needs_hdr) ? eWLFC_PKTTYPE_DELAYED : - eWLFC_PKTTYPE_SUPPRESSED; - - rc = _dhd_wlfc_handle_packet_commit(ctx, ac, &commit_info, - fcommit, commit_ctx); - - /* Bus commits may fail (e.g. flow control); abort after retries */ - if (rc == BCME_OK) { - if (commit_info.ac_fifo_credit_spent) { - (void) _dhd_wlfc_borrow_credit(ctx, ac_available, ac); - credit_count--; - } - } - else { - bus_retry_count++; - if (bus_retry_count >= BUS_RETRIES) { - DHD_ERROR(("dhd_wlfc_commit_packets(): bus error\n")); - return rc; - } - } - } - - return BCME_OK; -} - -static uint8 -dhd_wlfc_find_mac_desc_id_from_mac(dhd_pub_t *dhdp, uint8* ea) -{ - wlfc_mac_descriptor_t* table = - ((athost_wl_status_info_t*)dhdp->wlfc_state)->destination_entries.nodes; - uint8 table_index; - - if (ea != NULL) { - for (table_index = 0; table_index < WLFC_MAC_DESC_TABLE_SIZE; table_index++) { - if ((memcmp(ea, &table[table_index].ea[0], ETHER_ADDR_LEN) == 0) && - table[table_index].occupied) - return table_index; - } - } - return WLFC_MAC_DESC_ID_INVALID; -} - -void -dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success) -{ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - void* p; - int fifo_id; - - if (DHD_PKTTAG_SIGNALONLY(PKTTAG(txp))) { -#ifdef PROP_TXSTATUS_DEBUG - wlfc->stats.signal_only_pkts_freed++; -#endif - /* is this a signal-only packet? */ - PKTFREE(wlfc->osh, txp, TRUE); - return; - } - if (!success) { - WLFC_DBGMESG(("At: %s():%d, bus_complete() failure for %p, htod_tag:0x%08x\n", - __FUNCTION__, __LINE__, txp, DHD_PKTTAG_H2DTAG(PKTTAG(txp)))); - dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(DHD_PKTTAG_H2DTAG - (PKTTAG(txp))), &p, 1); - - /* indicate failure and free the packet */ - dhd_txcomplete(dhd, txp, FALSE); - - /* return the credit, if necessary */ - if (DHD_PKTTAG_CREDITCHECK(PKTTAG(txp))) { - int lender, credit_returned = 0; /* Note that borrower is fifo_id */ - - fifo_id = DHD_PKTTAG_FIFO(PKTTAG(txp)); - - /* Return credits to highest priority lender first */ - for (lender = AC_COUNT; lender >= 0; lender--) { - if (wlfc->credits_borrowed[fifo_id][lender] > 0) { - wlfc->FIFO_credit[lender]++; - wlfc->credits_borrowed[fifo_id][lender]--; - credit_returned = 1; - break; - } - } - - if (!credit_returned) { - wlfc->FIFO_credit[fifo_id]++; - } - } - - PKTFREE(wlfc->osh, txp, TRUE); - } - return; -} - -/* Handle discard or suppress indication */ -static int -dhd_wlfc_txstatus_update(dhd_pub_t *dhd, uint8* pkt_info) -{ - uint8 status_flag; - uint32 status; - int ret; - int remove_from_hanger = 1; - void* pktbuf; - uint8 fifo_id; - wlfc_mac_descriptor_t* entry = NULL; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - - memcpy(&status, pkt_info, sizeof(uint32)); - status_flag = WL_TXSTATUS_GET_FLAGS(status); - wlfc->stats.txstatus_in++; - - if (status_flag == WLFC_CTL_PKTFLAG_DISCARD) { - wlfc->stats.pkt_freed++; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) { - wlfc->stats.d11_suppress++; - remove_from_hanger = 0; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS) { - wlfc->stats.wl_suppress++; - remove_from_hanger = 0; - } - - else if (status_flag == WLFC_CTL_PKTFLAG_TOSSED_BYWLC) { - wlfc->stats.wlc_tossed_pkts++; - } - - ret = dhd_wlfc_hanger_poppkt(wlfc->hanger, - WLFC_PKTID_HSLOT_GET(status), &pktbuf, remove_from_hanger); - if (ret != BCME_OK) { - /* do something */ - return ret; - } - - entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); - - if (!remove_from_hanger) { - /* this packet was suppressed */ - if (!entry->suppressed || entry->generation != WLFC_PKTID_GEN(status)) { - entry->suppressed = TRUE; - entry->suppress_count = pktq_mlen(&entry->psq, - NBITVAL((WL_TXSTATUS_GET_FIFO(status) << 1) + 1)); - entry->suppr_transit_count = entry->transit_count; - } - entry->generation = WLFC_PKTID_GEN(status); - } - -#ifdef PROP_TXSTATUS_DEBUG - { - uint32 new_t = OSL_SYSUPTIME(); - uint32 old_t; - uint32 delta; - old_t = ((wlfc_hanger_t*)(wlfc->hanger))->items[ - WLFC_PKTID_HSLOT_GET(status)].push_time; - - - wlfc->stats.latency_sample_count++; - if (new_t > old_t) - delta = new_t - old_t; - else - delta = 0xffffffff + new_t - old_t; - wlfc->stats.total_status_latency += delta; - wlfc->stats.latency_most_recent = delta; - - wlfc->stats.deltas[wlfc->stats.idx_delta++] = delta; - if (wlfc->stats.idx_delta == sizeof(wlfc->stats.deltas)/sizeof(uint32)) - wlfc->stats.idx_delta = 0; - } -#endif /* PROP_TXSTATUS_DEBUG */ - - fifo_id = DHD_PKTTAG_FIFO(PKTTAG(pktbuf)); - - /* pick up the implicit credit from this packet */ - if (DHD_PKTTAG_CREDITCHECK(PKTTAG(pktbuf))) { - if (wlfc->proptxstatus_mode == WLFC_FCMODE_IMPLIED_CREDIT) { - - int lender, credit_returned = 0; /* Note that borrower is fifo_id */ - - /* Return credits to highest priority lender first */ - for (lender = AC_COUNT; lender >= 0; lender--) { - if (wlfc->credits_borrowed[fifo_id][lender] > 0) { - wlfc->FIFO_credit[lender]++; - wlfc->credits_borrowed[fifo_id][lender]--; - credit_returned = 1; - break; - } - } - - if (!credit_returned) { - wlfc->FIFO_credit[fifo_id]++; - } - } - } - else { - /* - if this packet did not count against FIFO credit, it must have - taken a requested_credit from the destination entry (for pspoll etc.) - */ - if (!entry) { - - entry = _dhd_wlfc_find_table_entry(wlfc, pktbuf); - } - if (!DHD_PKTTAG_ONETIMEPKTRQST(PKTTAG(pktbuf))) - entry->requested_credit++; -#ifdef PROP_TXSTATUS_DEBUG - entry->dstncredit_acks++; -#endif - } - if ((status_flag == WLFC_CTL_PKTFLAG_D11SUPPRESS) || - (status_flag == WLFC_CTL_PKTFLAG_WLSUPPRESS)) { - ret = _dhd_wlfc_enque_suppressed(wlfc, fifo_id, pktbuf); - if (ret != BCME_OK) { - /* delay q is full, drop this packet */ - dhd_wlfc_hanger_poppkt(wlfc->hanger, WLFC_PKTID_HSLOT_GET(status), - &pktbuf, 1); - - /* indicate failure and free the packet */ - dhd_txcomplete(dhd, pktbuf, FALSE); - entry->transit_count--; - /* This packet is transmitted Successfully by dongle even after first suppress. */ - if (entry->suppressed){ - entry->suppr_transit_count--; - } - PKTFREE(wlfc->osh, pktbuf, TRUE); - } else { - /* Mark suppressed to avoid a double free during wlfc cleanup */ - - dhd_wlfc_hanger_mark_suppressed(wlfc->hanger, - WLFC_PKTID_HSLOT_GET(status), WLFC_PKTID_GEN(status)); - entry->suppress_count++; - } - } - else { - dhd_txcomplete(dhd, pktbuf, TRUE); - entry->transit_count--; - - /* This packet is transmitted Successfully by dongle even after first suppress. */ - if (entry->suppressed){ - entry->suppr_transit_count--; - } - /* free the packet */ - PKTFREE(wlfc->osh, pktbuf, TRUE); - } - return BCME_OK; -} - -static int -dhd_wlfc_fifocreditback_indicate(dhd_pub_t *dhd, uint8* credits) -{ - int i; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - for (i = 0; i < WLFC_CTL_VALUE_LEN_FIFO_CREDITBACK; i++) { -#ifdef PROP_TXSTATUS_DEBUG - wlfc->stats.fifo_credits_back[i] += credits[i]; -#endif - /* update FIFO credits */ - if (wlfc->proptxstatus_mode == WLFC_FCMODE_EXPLICIT_CREDIT) - { - int lender; /* Note that borrower is i */ - - /* Return credits to highest priority lender first */ - for (lender = AC_COUNT; (lender >= 0) && (credits[i] > 0); lender--) { - if (wlfc->credits_borrowed[i][lender] > 0) { - if (credits[i] >= wlfc->credits_borrowed[i][lender]) { - credits[i] -= wlfc->credits_borrowed[i][lender]; - wlfc->FIFO_credit[lender] += - wlfc->credits_borrowed[i][lender]; - wlfc->credits_borrowed[i][lender] = 0; - } - else { - wlfc->credits_borrowed[i][lender] -= credits[i]; - wlfc->FIFO_credit[lender] += credits[i]; - credits[i] = 0; - } - } - } - - /* If we have more credits left over, these must belong to the AC */ - if (credits[i] > 0) { - wlfc->FIFO_credit[i] += credits[i]; - } - } - } - - return BCME_OK; -} - -static int -dhd_wlfc_rssi_indicate(dhd_pub_t *dhd, uint8* rssi) -{ - (void)dhd; - (void)rssi; - return BCME_OK; -} - -static int -dhd_wlfc_mac_table_update(dhd_pub_t *dhd, uint8* value, uint8 type) -{ - int rc; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - uint8 existing_index; - uint8 table_index; - uint8 ifid; - uint8* ea; - - WLFC_DBGMESG(("%s(), mac [%02x:%02x:%02x:%02x:%02x:%02x],%s,idx:%d,id:0x%02x\n", - __FUNCTION__, value[2], value[3], value[4], value[5], value[6], value[7], - ((type == WLFC_CTL_TYPE_MACDESC_ADD) ? "ADD":"DEL"), - WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]), value[0])); - - table = wlfc->destination_entries.nodes; - table_index = WLFC_MAC_DESC_GET_LOOKUP_INDEX(value[0]); - ifid = value[1]; - ea = &value[2]; - - if (type == WLFC_CTL_TYPE_MACDESC_ADD) { - existing_index = dhd_wlfc_find_mac_desc_id_from_mac(dhd, &value[2]); - if (existing_index == WLFC_MAC_DESC_ID_INVALID) { - /* this MAC entry does not exist, create one */ - if (!table[table_index].occupied) { - table[table_index].mac_handle = value[0]; - rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], - eWLFC_MAC_ENTRY_ACTION_ADD, ifid, - wlfc->destination_entries.interfaces[ifid].iftype, - ea); - } - else { - /* the space should have been empty, but it's not */ - wlfc->stats.mac_update_failed++; - } - } - else { - /* - there is an existing entry, move it to new index - if necessary. - */ - if (existing_index != table_index) { - /* if we already have an entry, free the old one */ - table[existing_index].occupied = 0; - table[existing_index].state = WLFC_STATE_CLOSE; - table[existing_index].requested_credit = 0; - table[existing_index].interface_id = 0; - /* enable after packets are queued-deqeued properly. - pktq_flush(dhd->osh, &table[existing_index].psq, FALSE, NULL, 0); - */ - } - } - } - if (type == WLFC_CTL_TYPE_MACDESC_DEL) { - if (table[table_index].occupied) { - rc = _dhd_wlfc_mac_entry_update(wlfc, &table[table_index], - eWLFC_MAC_ENTRY_ACTION_DEL, ifid, - wlfc->destination_entries.interfaces[ifid].iftype, - ea); - } - else { - /* the space should have been occupied, but it's not */ - wlfc->stats.mac_update_failed++; - } - } - BCM_REFERENCE(rc); - return BCME_OK; -} - -static int -dhd_wlfc_psmode_update(dhd_pub_t *dhd, uint8* value, uint8 type) -{ - /* Handle PS on/off indication */ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_mac_descriptor_t* desc; - uint8 mac_handle = value[0]; - int i; - - table = wlfc->destination_entries.nodes; - desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; - if (desc->occupied) { - /* a fresh PS mode should wipe old ps credits? */ - desc->requested_credit = 0; - if (type == WLFC_CTL_TYPE_MAC_OPEN) { - desc->state = WLFC_STATE_OPEN; - DHD_WLFC_CTRINC_MAC_OPEN(desc); - } - else { - desc->state = WLFC_STATE_CLOSE; - DHD_WLFC_CTRINC_MAC_CLOSE(desc); - /* - Indicate to firmware if there is any traffic pending. - */ - for (i = AC_BE; i < AC_COUNT; i++) { - _dhd_wlfc_traffic_pending_check(wlfc, desc, i); - } - } - } - else { - wlfc->stats.psmode_update_failed++; - } - return BCME_OK; -} - -static int -dhd_wlfc_interface_update(dhd_pub_t *dhd, uint8* value, uint8 type) -{ - /* Handle PS on/off indication */ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - uint8 if_id = value[0]; - - if (if_id < WLFC_MAX_IFNUM) { - table = wlfc->destination_entries.interfaces; - if (table[if_id].occupied) { - if (type == WLFC_CTL_TYPE_INTERFACE_OPEN) { - table[if_id].state = WLFC_STATE_OPEN; - /* WLFC_DBGMESG(("INTERFACE[%d] OPEN\n", if_id)); */ - } - else { - table[if_id].state = WLFC_STATE_CLOSE; - /* WLFC_DBGMESG(("INTERFACE[%d] CLOSE\n", if_id)); */ - } - return BCME_OK; - } - } - wlfc->stats.interface_update_failed++; - - return BCME_OK; -} - -static int -dhd_wlfc_credit_request(dhd_pub_t *dhd, uint8* value) -{ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_mac_descriptor_t* desc; - uint8 mac_handle; - uint8 credit; - - table = wlfc->destination_entries.nodes; - mac_handle = value[1]; - credit = value[0]; - - desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; - if (desc->occupied) { - desc->requested_credit = credit; - - desc->ac_bitmap = value[2]; - } - else { - wlfc->stats.credit_request_failed++; - } - return BCME_OK; -} - -static int -dhd_wlfc_packet_request(dhd_pub_t *dhd, uint8* value) -{ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_mac_descriptor_t* desc; - uint8 mac_handle; - uint8 packet_count; - - table = wlfc->destination_entries.nodes; - mac_handle = value[1]; - packet_count = value[0]; - - desc = &table[WLFC_MAC_DESC_GET_LOOKUP_INDEX(mac_handle)]; - if (desc->occupied) { - desc->requested_packet = packet_count; - - desc->ac_bitmap = value[2]; - } - else { - wlfc->stats.packet_request_failed++; - } - return BCME_OK; -} - -static void -dhd_wlfc_reorderinfo_indicate(uint8 *val, uint8 len, uchar *info_buf, uint *info_len) -{ - if (info_len) { - if (info_buf) { - bcopy(val, info_buf, len); - *info_len = len; - } - else - *info_len = 0; - } -} - -static int -dhd_wlfc_parse_header_info(dhd_pub_t *dhd, void* pktbuf, int tlv_hdr_len, uchar *reorder_info_buf, - uint *reorder_info_len) -{ - uint8 type, len; - uint8* value; - uint8* tmpbuf; - uint16 remainder = tlv_hdr_len; - uint16 processed = 0; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - tmpbuf = (uint8*)PKTDATA(dhd->osh, pktbuf); - if (remainder) { - while ((processed < (WLFC_MAX_PENDING_DATALEN * 2)) && (remainder > 0)) { - type = tmpbuf[processed]; - if (type == WLFC_CTL_TYPE_FILLER) { - remainder -= 1; - processed += 1; - continue; - } - - len = tmpbuf[processed + 1]; - value = &tmpbuf[processed + 2]; - - if (remainder < (2 + len)) - break; - - remainder -= 2 + len; - processed += 2 + len; - if (type == WLFC_CTL_TYPE_TXSTATUS) - dhd_wlfc_txstatus_update(dhd, value); - - else if (type == WLFC_CTL_TYPE_HOST_REORDER_RXPKTS) - dhd_wlfc_reorderinfo_indicate(value, len, reorder_info_buf, - reorder_info_len); - else if (type == WLFC_CTL_TYPE_FIFO_CREDITBACK) - dhd_wlfc_fifocreditback_indicate(dhd, value); - - else if (type == WLFC_CTL_TYPE_RSSI) - dhd_wlfc_rssi_indicate(dhd, value); - - else if (type == WLFC_CTL_TYPE_MAC_REQUEST_CREDIT) - dhd_wlfc_credit_request(dhd, value); - - else if (type == WLFC_CTL_TYPE_MAC_REQUEST_PACKET) - dhd_wlfc_packet_request(dhd, value); - - else if ((type == WLFC_CTL_TYPE_MAC_OPEN) || - (type == WLFC_CTL_TYPE_MAC_CLOSE)) - dhd_wlfc_psmode_update(dhd, value, type); - - else if ((type == WLFC_CTL_TYPE_MACDESC_ADD) || - (type == WLFC_CTL_TYPE_MACDESC_DEL)) - dhd_wlfc_mac_table_update(dhd, value, type); - - else if ((type == WLFC_CTL_TYPE_INTERFACE_OPEN) || - (type == WLFC_CTL_TYPE_INTERFACE_CLOSE)) { - dhd_wlfc_interface_update(dhd, value, type); - } - } - if (remainder != 0) { - /* trouble..., something is not right */ - wlfc->stats.tlv_parse_failed++; - } - } - return BCME_OK; -} - -int -dhd_wlfc_init(dhd_pub_t *dhd) -{ - char iovbuf[12]; /* Room for "tlv" + '\0' + parameter */ - /* enable all signals & indicate host proptxstatus logic is active */ - uint32 tlv = dhd->wlfc_enabled? - WLFC_FLAGS_RSSI_SIGNALS | - WLFC_FLAGS_XONXOFF_SIGNALS | - WLFC_FLAGS_CREDIT_STATUS_SIGNALS | - WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | - WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; - /* WLFC_FLAGS_HOST_PROPTXSTATUS_ACTIVE | WLFC_FLAGS_HOST_RXRERODER_ACTIVE : 0; */ - - - /* - try to enable/disable signaling by sending "tlv" iovar. if that fails, - fallback to no flow control? Print a message for now. - */ - - /* enable proptxtstatus signaling by default */ - bcm_mkiovar("tlv", (char *)&tlv, 4, iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) < 0) { - DHD_ERROR(("dhd_wlfc_init(): failed to enable/disable bdcv2 tlv signaling\n")); - } - else { - /* - Leaving the message for now, it should be removed after a while; once - the tlv situation is stable. - */ - DHD_ERROR(("dhd_wlfc_init(): successfully %s bdcv2 tlv signaling, %d\n", - dhd->wlfc_enabled?"enabled":"disabled", tlv)); - } - return BCME_OK; -} - -int -dhd_wlfc_enable(dhd_pub_t *dhd) -{ - int i; - athost_wl_status_info_t* wlfc; - - if (!dhd->wlfc_enabled || dhd->wlfc_state) - return BCME_OK; - - /* allocate space to track txstatus propagated from firmware */ - dhd->wlfc_state = MALLOC(dhd->osh, sizeof(athost_wl_status_info_t)); - if (dhd->wlfc_state == NULL) - return BCME_NOMEM; - - /* initialize state space */ - wlfc = (athost_wl_status_info_t*)dhd->wlfc_state; - memset(wlfc, 0, sizeof(athost_wl_status_info_t)); - - /* remember osh & dhdp */ - wlfc->osh = dhd->osh; - wlfc->dhdp = dhd; - - wlfc->hanger = - dhd_wlfc_hanger_create(dhd->osh, WLFC_HANGER_MAXITEMS); - if (wlfc->hanger == NULL) { - MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); - dhd->wlfc_state = NULL; - return BCME_NOMEM; - } - - /* initialize all interfaces to accept traffic */ - for (i = 0; i < WLFC_MAX_IFNUM; i++) { - wlfc->hostif_flow_state[i] = OFF; - } - - /* - create the SENDQ containing - sub-queues for all AC precedences + 1 for bc/mc traffic - */ - pktq_init(&wlfc->SENDQ, (AC_COUNT + 1), WLFC_SENDQ_LEN); - - wlfc->destination_entries.other.state = WLFC_STATE_OPEN; - /* bc/mc FIFO is always open [credit aside], i.e. b[5] */ - wlfc->destination_entries.other.ac_bitmap = 0x1f; - wlfc->destination_entries.other.interface_id = 0; - - wlfc->proptxstatus_mode = WLFC_FCMODE_EXPLICIT_CREDIT; - - wlfc->allow_credit_borrow = TRUE; - wlfc->borrow_defer_timestamp = 0; -#ifdef VSDB_DYNAMIC_F2_BLKSIZE - dhdsdio_func_blocksize(dhd, 2, VSDB_F2_BLKSIZE); -#endif - return BCME_OK; -} - -/* release all packet resources */ -void -dhd_wlfc_cleanup(dhd_pub_t *dhd) -{ - int i; - int total_entries; - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - wlfc_mac_descriptor_t* table; - wlfc_hanger_t* h; - - if (dhd->wlfc_state == NULL) - return; - - total_entries = sizeof(wlfc->destination_entries)/sizeof(wlfc_mac_descriptor_t); - /* search all entries, include nodes as well as interfaces */ - table = (wlfc_mac_descriptor_t*)&wlfc->destination_entries; - - for (i = 0; i < total_entries; i++) { - if (table[i].occupied) { - if (table[i].psq.len) { - WLFC_DBGMESG(("%s(): DELAYQ[%d].len = %d\n", - __FUNCTION__, i, table[i].psq.len)); - /* release packets held in DELAYQ */ - pktq_flush(wlfc->osh, &table[i].psq, TRUE, NULL, 0); - } - table[i].occupied = 0; - } - } - /* release packets held in SENDQ */ - if (wlfc->SENDQ.len) - pktq_flush(wlfc->osh, &wlfc->SENDQ, TRUE, NULL, 0); - /* any in the hanger? */ - h = (wlfc_hanger_t*)wlfc->hanger; - for (i = 0; i < h->max_items; i++) { - if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE) { - PKTFREE(wlfc->osh, h->items[i].pkt, TRUE); - h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - } else if (h->items[i].state == WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED) { - /* These are freed from the psq so no need to free again */ - h->items[i].state = WLFC_HANGER_ITEM_STATE_FREE; - } - } - return; -} - -void -dhd_wlfc_deinit(dhd_pub_t *dhd) -{ - /* cleanup all psq related resources */ - athost_wl_status_info_t* wlfc = (athost_wl_status_info_t*) - dhd->wlfc_state; - - if (dhd->wlfc_state == NULL) - return; - -#ifdef PROP_TXSTATUS_DEBUG - { - int i; - wlfc_hanger_t* h = (wlfc_hanger_t*)wlfc->hanger; - for (i = 0; i < h->max_items; i++) { - if (h->items[i].state != WLFC_HANGER_ITEM_STATE_FREE) { - WLFC_DBGMESG(("%s() pkt[%d] = 0x%p, FIFO_credit_used:%d\n", - __FUNCTION__, i, h->items[i].pkt, - DHD_PKTTAG_CREDITCHECK(PKTTAG(h->items[i].pkt)))); - } - } - } -#endif - /* delete hanger */ - dhd_wlfc_hanger_delete(dhd->osh, wlfc->hanger); - - /* free top structure */ - MFREE(dhd->osh, dhd->wlfc_state, sizeof(athost_wl_status_info_t)); - dhd->wlfc_state = NULL; -#ifdef VSDB_DYNAMIC_F2_BLKSIZE - dhdsdio_func_blocksize(dhd, 2, sd_f2_blocksize); -#endif - return; -} -#endif /* PROP_TXSTATUS */ - -void -dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - bcm_bprintf(strbuf, "Protocol CDC: reqid %d\n", dhdp->prot->reqid); -#ifdef PROP_TXSTATUS - if (dhdp->wlfc_state) - dhd_wlfc_dump(dhdp, strbuf); -#endif -} - -void -dhd_prot_hdrpush(dhd_pub_t *dhd, int ifidx, void *pktbuf) -{ -#ifdef BDC - struct bdc_header *h; -#endif /* BDC */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#ifdef BDC - /* Push BDC header used to convey priority for buses that don't */ - - PKTPUSH(dhd->osh, pktbuf, BDC_HEADER_LEN); - - h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); - - h->flags = (BDC_PROTO_VER << BDC_FLAG_VER_SHIFT); - if (PKTSUMNEEDED(pktbuf)) - h->flags |= BDC_FLAG_SUM_NEEDED; - - - h->priority = (PKTPRIO(pktbuf) & BDC_PRIORITY_MASK); - h->flags2 = 0; - h->dataOffset = 0; -#endif /* BDC */ - BDC_SET_IF_IDX(h, ifidx); -} - -int -dhd_prot_hdrpull(dhd_pub_t *dhd, int *ifidx, void *pktbuf, uchar *reorder_buf_info, - uint *reorder_info_len) -{ -#ifdef BDC - struct bdc_header *h; -#endif - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#ifdef BDC - if (reorder_info_len) - *reorder_info_len = 0; - /* Pop BDC header used to convey priority for buses that don't */ - - if (PKTLEN(dhd->osh, pktbuf) < BDC_HEADER_LEN) { - DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, - PKTLEN(dhd->osh, pktbuf), BDC_HEADER_LEN)); - return BCME_ERROR; - } - - h = (struct bdc_header *)PKTDATA(dhd->osh, pktbuf); - - if ((*ifidx = BDC_GET_IF_IDX(h)) >= DHD_MAX_IFS) { - DHD_ERROR(("%s: rx data ifnum out of range (%d)\n", - __FUNCTION__, *ifidx)); - return BCME_ERROR; - } - -#if defined(NDIS630) - h->dataOffset = 0; -#endif - if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) != BDC_PROTO_VER) { - DHD_ERROR(("%s: non-BDC packet received, flags = 0x%x\n", - dhd_ifname(dhd, *ifidx), h->flags)); - if (((h->flags & BDC_FLAG_VER_MASK) >> BDC_FLAG_VER_SHIFT) == BDC_PROTO_VER_1) - h->dataOffset = 0; - else - return BCME_ERROR; - } - - if (h->flags & BDC_FLAG_SUM_GOOD) { - DHD_INFO(("%s: BDC packet received with good rx-csum, flags 0x%x\n", - dhd_ifname(dhd, *ifidx), h->flags)); - PKTSETSUMGOOD(pktbuf, TRUE); - } - - PKTSETPRIO(pktbuf, (h->priority & BDC_PRIORITY_MASK)); - PKTPULL(dhd->osh, pktbuf, BDC_HEADER_LEN); -#endif /* BDC */ - -#if !defined(NDIS630) - if (PKTLEN(dhd->osh, pktbuf) < (uint32) (h->dataOffset << 2)) { - DHD_ERROR(("%s: rx data too short (%d < %d)\n", __FUNCTION__, - PKTLEN(dhd->osh, pktbuf), (h->dataOffset * 4))); - return BCME_ERROR; - } -#endif -#ifdef PROP_TXSTATUS - if (dhd->wlfc_state && - ((athost_wl_status_info_t*)dhd->wlfc_state)->proptxstatus_mode - != WLFC_FCMODE_NONE && - (!DHD_PKTTAG_PKTDIR(PKTTAG(pktbuf)))) { - /* - - parse txstatus only for packets that came from the firmware - */ - dhd_os_wlfc_block(dhd); - dhd_wlfc_parse_header_info(dhd, pktbuf, (h->dataOffset << 2), - reorder_buf_info, reorder_info_len); - ((athost_wl_status_info_t*)dhd->wlfc_state)->stats.dhd_hdrpulls++; - dhd_wlfc_commit_packets(dhd->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, - (void *)dhd->bus); - dhd_os_wlfc_unblock(dhd); - } -#endif /* PROP_TXSTATUS */ -#if !defined(NDIS630) - PKTPULL(dhd->osh, pktbuf, (h->dataOffset << 2)); -#endif - return 0; -} - -int -dhd_prot_attach(dhd_pub_t *dhd) -{ - dhd_prot_t *cdc; - - if (!(cdc = (dhd_prot_t *)DHD_OS_PREALLOC(dhd->osh, DHD_PREALLOC_PROT, - sizeof(dhd_prot_t)))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - goto fail; - } - memset(cdc, 0, sizeof(dhd_prot_t)); - - /* ensure that the msg buf directly follows the cdc msg struct */ - if ((uintptr)(&cdc->msg + 1) != (uintptr)cdc->buf) { - DHD_ERROR(("dhd_prot_t is not correctly defined\n")); - goto fail; - } - - dhd->prot = cdc; -#ifdef BDC - dhd->hdrlen += BDC_HEADER_LEN; -#endif - dhd->maxctl = WLC_IOCTL_MAXLEN + sizeof(cdc_ioctl_t) + ROUND_UP_MARGIN; - return 0; - -fail: -#ifndef CONFIG_DHD_USE_STATIC_BUF - if (cdc != NULL) - MFREE(dhd->osh, cdc, sizeof(dhd_prot_t)); -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - return BCME_NOMEM; -} - -/* ~NOTE~ What if another thread is waiting on the semaphore? Holding it? */ -void -dhd_prot_detach(dhd_pub_t *dhd) -{ -#ifdef PROP_TXSTATUS - dhd_wlfc_deinit(dhd); -#endif -#ifndef CONFIG_DHD_USE_STATIC_BUF - MFREE(dhd->osh, dhd->prot, sizeof(dhd_prot_t)); -#endif /* CONFIG_DHD_USE_STATIC_BUF */ - dhd->prot = NULL; -} - -void -dhd_prot_dstats(dhd_pub_t *dhd) -{ - /* No stats from dongle added yet, copy bus stats */ - dhd->dstats.tx_packets = dhd->tx_packets; - dhd->dstats.tx_errors = dhd->tx_errors; - dhd->dstats.rx_packets = dhd->rx_packets; - dhd->dstats.rx_errors = dhd->rx_errors; - dhd->dstats.rx_dropped = dhd->rx_dropped; - dhd->dstats.multicast = dhd->rx_multicast; - return; -} - -int -dhd_prot_init(dhd_pub_t *dhd) -{ - int ret = 0; - wlc_rev_info_t revinfo; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - - /* Get the device rev info */ - memset(&revinfo, 0, sizeof(revinfo)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_REVINFO, &revinfo, sizeof(revinfo), FALSE, 0); - if (ret < 0) - goto done; - - -#ifdef PROP_TXSTATUS - ret = dhd_wlfc_init(dhd); -#endif - -#if defined(WL_CFG80211) - if (dhd_download_fw_on_driverload) -#endif /* defined(WL_CFG80211) */ - ret = dhd_preinit_ioctls(dhd); - - /* Always assumes wl for now */ - dhd->iswl = TRUE; - -done: - return ret; -} - -void -dhd_prot_stop(dhd_pub_t *dhd) -{ - /* Nothing to do for CDC */ -} - - -static void -dhd_get_hostreorder_pkts(void *osh, struct reorder_info *ptr, void **pkt, - uint32 *pkt_count, void **pplast, uint8 start, uint8 end) -{ - uint i; - void *plast = NULL, *p; - uint32 pkt_cnt = 0; - - if (ptr->pend_pkts == 0) { - DHD_REORDER(("%s: no packets in reorder queue \n", __FUNCTION__)); - *pplast = NULL; - *pkt_count = 0; - *pkt = NULL; - return; - } - if (start == end) - i = ptr->max_idx + 1; - else { - if (start > end) - i = (ptr->max_idx - end) + start; - else - i = end - start; - } - while (i) { - p = (void *)(ptr->p[start]); - ptr->p[start] = NULL; - - if (p != NULL) { - if (plast == NULL) - *pkt = p; - else - PKTSETNEXT(dhd->osh, plast, p); - - plast = p; - pkt_cnt++; - } - i--; - if (start++ == ptr->max_idx) - start = 0; - } - *pplast = plast; - *pkt_count = (uint32)pkt_cnt; -} - -int -dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, uint reorder_info_len, - void **pkt, uint32 *pkt_count) -{ - uint8 flow_id, max_idx, cur_idx, exp_idx; - struct reorder_info *ptr; - uint8 flags; - void *cur_pkt, *plast = NULL; - uint32 cnt = 0; - - if (pkt == NULL) { - if (pkt_count != NULL) - *pkt_count = 0; - return 0; - } - cur_pkt = *pkt; - *pkt = NULL; - - flow_id = reorder_info_buf[WLHOST_REORDERDATA_FLOWID_OFFSET]; - flags = reorder_info_buf[WLHOST_REORDERDATA_FLAGS_OFFSET]; - - DHD_REORDER(("flow_id %d, flags 0x%02x, idx(%d, %d, %d)\n", flow_id, flags, - reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET], - reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET], - reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET])); - - /* validate flags and flow id */ - if (flags == 0xFF) { - DHD_ERROR(("%s: invalid flags...so ignore this packet\n", __FUNCTION__)); - *pkt_count = 1; - return 0; - } - - ptr = dhd->reorder_bufs[flow_id]; - if (flags & WLHOST_REORDERDATA_DEL_FLOW) { - uint32 buf_size = sizeof(struct reorder_info); - - DHD_REORDER(("%s: Flags indicating to delete a flow id %d\n", - __FUNCTION__, flow_id)); - - if (ptr == NULL) { - DHD_ERROR(("%s: received flags to cleanup, but no flow (%d) yet\n", - __FUNCTION__, flow_id)); - *pkt_count = 1; - return 0; - } - - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, - ptr->exp_idx, ptr->exp_idx); - /* set it to the last packet */ - if (plast) { - PKTSETNEXT(dhd->osh, plast, cur_pkt); - cnt++; - } - else { - if (cnt != 0) { - DHD_ERROR(("%s: del flow: something fishy, pending packets %d\n", - __FUNCTION__, cnt)); - } - *pkt = cur_pkt; - cnt = 1; - } - buf_size += ((ptr->max_idx + 1) * sizeof(void *)); - MFREE(dhd->osh, ptr, buf_size); - dhd->reorder_bufs[flow_id] = NULL; - *pkt_count = cnt; - return 0; - } - /* all the other cases depend on the existance of the reorder struct for that flow id */ - if (ptr == NULL) { - uint32 buf_size_alloc = sizeof(reorder_info_t); - max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; - - buf_size_alloc += ((max_idx + 1) * sizeof(void*)); - /* allocate space to hold the buffers, index etc */ - - DHD_REORDER(("%s: alloc buffer of size %d size, reorder info id %d, maxidx %d\n", - __FUNCTION__, buf_size_alloc, flow_id, max_idx)); - ptr = (struct reorder_info *)MALLOC(dhd->osh, buf_size_alloc); - if (ptr == NULL) { - DHD_ERROR(("%s: Malloc failed to alloc buffer\n", __FUNCTION__)); - *pkt_count = 1; - return 0; - } - bzero(ptr, buf_size_alloc); - dhd->reorder_bufs[flow_id] = ptr; - ptr->p = (void *)(ptr+1); - ptr->max_idx = max_idx; - } - if (flags & WLHOST_REORDERDATA_NEW_HOLE) { - DHD_REORDER(("%s: new hole, so cleanup pending buffers\n", __FUNCTION__)); - if (ptr->pend_pkts) { - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, - ptr->exp_idx, ptr->exp_idx); - ptr->pend_pkts = 0; - } - ptr->cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; - ptr->exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; - ptr->max_idx = reorder_info_buf[WLHOST_REORDERDATA_MAXIDX_OFFSET]; - ptr->p[ptr->cur_idx] = cur_pkt; - ptr->pend_pkts++; - *pkt_count = cnt; - } - else if (flags & WLHOST_REORDERDATA_CURIDX_VALID) { - cur_idx = reorder_info_buf[WLHOST_REORDERDATA_CURIDX_OFFSET]; - exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; - - - if ((exp_idx == ptr->exp_idx) && (cur_idx != ptr->exp_idx)) { - /* still in the current hole */ - /* enqueue the current on the buffer chain */ - if (ptr->p[cur_idx] != NULL) { - DHD_REORDER(("%s: HOLE: ERROR buffer pending..free it\n", - __FUNCTION__)); - PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); - ptr->p[cur_idx] = NULL; - } - ptr->p[cur_idx] = cur_pkt; - ptr->pend_pkts++; - ptr->cur_idx = cur_idx; - DHD_REORDER(("%s: fill up a hole..pending packets is %d\n", - __FUNCTION__, ptr->pend_pkts)); - *pkt_count = 0; - *pkt = NULL; - } - else if (ptr->exp_idx == cur_idx) { - /* got the right one ..flush from cur to exp and update exp */ - DHD_REORDER(("%s: got the right one now, cur_idx is %d\n", - __FUNCTION__, cur_idx)); - if (ptr->p[cur_idx] != NULL) { - DHD_REORDER(("%s: Error buffer pending..free it\n", - __FUNCTION__)); - PKTFREE(dhd->osh, ptr->p[cur_idx], TRUE); - ptr->p[cur_idx] = NULL; - } - ptr->p[cur_idx] = cur_pkt; - ptr->pend_pkts++; - - ptr->cur_idx = cur_idx; - ptr->exp_idx = exp_idx; - - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, - cur_idx, exp_idx); - ptr->pend_pkts -= (uint8)cnt; - *pkt_count = cnt; - DHD_REORDER(("%s: freeing up buffers %d, still pending %d\n", - __FUNCTION__, cnt, ptr->pend_pkts)); - } - else { - uint8 end_idx; - bool flush_current = FALSE; - /* both cur and exp are moved now .. */ - DHD_REORDER(("%s:, flow %d, both moved, cur %d(%d), exp %d(%d)\n", - __FUNCTION__, flow_id, ptr->cur_idx, cur_idx, - ptr->exp_idx, exp_idx)); - if (flags & WLHOST_REORDERDATA_FLUSH_ALL) - end_idx = ptr->exp_idx; - else - end_idx = exp_idx; - - /* flush pkts first */ - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, - ptr->exp_idx, end_idx); - - if (cur_idx == ptr->max_idx) { - if (exp_idx == 0) - flush_current = TRUE; - } else { - if (exp_idx == cur_idx + 1) - flush_current = TRUE; - } - if (flush_current) { - if (plast) - PKTSETNEXT(dhd->osh, plast, cur_pkt); - else - *pkt = cur_pkt; - cnt++; - } - else { - ptr->p[cur_idx] = cur_pkt; - ptr->pend_pkts++; - } - ptr->exp_idx = exp_idx; - ptr->cur_idx = cur_idx; - *pkt_count = cnt; - } - } - else { - uint8 end_idx; - /* no real packet but update to exp_seq...that means explicit window move */ - exp_idx = reorder_info_buf[WLHOST_REORDERDATA_EXPIDX_OFFSET]; - - DHD_REORDER(("%s: move the window, cur_idx is %d, exp is %d, new exp is %d\n", - __FUNCTION__, ptr->cur_idx, ptr->exp_idx, exp_idx)); - if (flags & WLHOST_REORDERDATA_FLUSH_ALL) - end_idx = ptr->exp_idx; - else - end_idx = exp_idx; - - dhd_get_hostreorder_pkts(dhd->osh, ptr, pkt, &cnt, &plast, ptr->exp_idx, end_idx); - ptr->pend_pkts -= (uint8)cnt; - if (plast) - PKTSETNEXT(dhd->osh, plast, cur_pkt); - else - *pkt = cur_pkt; - cnt++; - *pkt_count = cnt; - /* set the new expected idx */ - ptr->exp_idx = exp_idx; - } - return 0; -} diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_cfg80211.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_cfg80211.c deleted file mode 100644 index 61369cb..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_cfg80211.c +++ /dev/null @@ -1,638 +0,0 @@ -/* - * Linux cfg80211 driver - Dongle Host Driver (DHD) related - * - * Copyright (C) 1999-2012, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ - */ - -#include <net/rtnetlink.h> - -#include <bcmutils.h> -#include <wldev_common.h> -#include <wl_cfg80211.h> -#include <dhd_cfg80211.h> - -#ifdef PKT_FILTER_SUPPORT -#include <dngl_stats.h> -#include <dhd.h> -#endif - -extern struct wl_priv *wlcfg_drv_priv; - -#ifdef PKT_FILTER_SUPPORT -extern uint dhd_pkt_filter_enable; -extern uint dhd_master_mode; -extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); -#endif - -static int dhd_dongle_up = FALSE; - -static s32 wl_dongle_up(struct net_device *ndev, u32 up); - -/** - * Function implementations - */ - -s32 dhd_cfg80211_init(struct wl_priv *wl) -{ - dhd_dongle_up = FALSE; - return 0; -} - -s32 dhd_cfg80211_deinit(struct wl_priv *wl) -{ - dhd_dongle_up = FALSE; - return 0; -} - -s32 dhd_cfg80211_down(struct wl_priv *wl) -{ - dhd_dongle_up = FALSE; - return 0; -} - -static s32 wl_dongle_up(struct net_device *ndev, u32 up) -{ - s32 err = 0; - - err = wldev_ioctl(ndev, WLC_UP, &up, sizeof(up), true); - if (unlikely(err)) { - WL_ERR(("WLC_UP error (%d)\n", err)); - } - return err; -} -s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock) -{ -#ifndef DHD_SDALIGN -#define DHD_SDALIGN 32 -#endif - struct net_device *ndev; - s32 err = 0; - - WL_TRACE(("In\n")); - if (dhd_dongle_up) { - WL_ERR(("Dongle is already up\n")); - return err; - } - - ndev = wl_to_prmry_ndev(wl); - - if (need_lock) - rtnl_lock(); - - err = wl_dongle_up(ndev, 0); - if (unlikely(err)) { - WL_ERR(("wl_dongle_up failed\n")); - goto default_conf_out; - } - dhd_dongle_up = true; - -default_conf_out: - if (need_lock) - rtnl_unlock(); - return err; - -} - - -/* TODO: clean up the BT-Coex code, it still have some legacy ioctl/iovar functions */ -#define COEX_DHCP - -#if defined(COEX_DHCP) - -/* use New SCO/eSCO smart YG suppression */ -#define BT_DHCP_eSCO_FIX -/* this flag boost wifi pkt priority to max, caution: -not fair to sco */ -#define BT_DHCP_USE_FLAGS -/* T1 start SCO/ESCo priority suppression */ -#define BT_DHCP_OPPR_WIN_TIME 2500 -/* T2 turn off SCO/SCO supperesion is (timeout) */ -#define BT_DHCP_FLAG_FORCE_TIME 5500 - -enum wl_cfg80211_btcoex_status { - BT_DHCP_IDLE, - BT_DHCP_START, - BT_DHCP_OPPR_WIN, - BT_DHCP_FLAG_FORCE_TIMEOUT -}; - -/* - * get named driver variable to uint register value and return error indication - * calling example: dev_wlc_intvar_get_reg(dev, "btc_params",66, ®_value) - */ -static int -dev_wlc_intvar_get_reg(struct net_device *dev, char *name, - uint reg, int *retval) -{ - union { - char buf[WLC_IOCTL_SMLEN]; - int val; - } var; - int error; - - bcm_mkiovar(name, (char *)(®), sizeof(reg), - (char *)(&var), sizeof(var.buf)); - error = wldev_ioctl(dev, WLC_GET_VAR, (char *)(&var), sizeof(var.buf), false); - - *retval = dtoh32(var.val); - return (error); -} - -static int -dev_wlc_bufvar_set(struct net_device *dev, char *name, char *buf, int len) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) - char ioctlbuf_local[1024]; -#else - static char ioctlbuf_local[1024]; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - - bcm_mkiovar(name, buf, len, ioctlbuf_local, sizeof(ioctlbuf_local)); - - return (wldev_ioctl(dev, WLC_SET_VAR, ioctlbuf_local, sizeof(ioctlbuf_local), true)); -} -/* -get named driver variable to uint register value and return error indication -calling example: dev_wlc_intvar_set_reg(dev, "btc_params",66, value) -*/ -static int -dev_wlc_intvar_set_reg(struct net_device *dev, char *name, char *addr, char * val) -{ - char reg_addr[8]; - - memset(reg_addr, 0, sizeof(reg_addr)); - memcpy((char *)®_addr[0], (char *)addr, 4); - memcpy((char *)®_addr[4], (char *)val, 4); - - return (dev_wlc_bufvar_set(dev, name, (char *)®_addr[0], sizeof(reg_addr))); -} - -static bool btcoex_is_sco_active(struct net_device *dev) -{ - int ioc_res = 0; - bool res = FALSE; - int sco_id_cnt = 0; - int param27; - int i; - - for (i = 0; i < 12; i++) { - - ioc_res = dev_wlc_intvar_get_reg(dev, "btc_params", 27, ¶m27); - - WL_TRACE(("%s, sample[%d], btc params: 27:%x\n", - __FUNCTION__, i, param27)); - - if (ioc_res < 0) { - WL_ERR(("%s ioc read btc params error\n", __FUNCTION__)); - break; - } - - if ((param27 & 0x6) == 2) { /* count both sco & esco */ - sco_id_cnt++; - } - - if (sco_id_cnt > 2) { - WL_TRACE(("%s, sco/esco detected, pkt id_cnt:%d samples:%d\n", - __FUNCTION__, sco_id_cnt, i)); - res = TRUE; - break; - } - - msleep(5); - } - - return res; -} - -#if defined(BT_DHCP_eSCO_FIX) -/* Enhanced BT COEX settings for eSCO compatibility during DHCP window */ -static int set_btc_esco_params(struct net_device *dev, bool trump_sco) -{ - static bool saved_status = FALSE; - - char buf_reg50va_dhcp_on[8] = - { 50, 00, 00, 00, 0x22, 0x80, 0x00, 0x00 }; - char buf_reg51va_dhcp_on[8] = - { 51, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg64va_dhcp_on[8] = - { 64, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg65va_dhcp_on[8] = - { 65, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - char buf_reg71va_dhcp_on[8] = - { 71, 00, 00, 00, 0x00, 0x00, 0x00, 0x00 }; - uint32 regaddr; - static uint32 saved_reg50; - static uint32 saved_reg51; - static uint32 saved_reg64; - static uint32 saved_reg65; - static uint32 saved_reg71; - - if (trump_sco) { - /* this should reduce eSCO agressive retransmit - * w/o breaking it - */ - - /* 1st save current */ - WL_TRACE(("Do new SCO/eSCO coex algo {save &" - "override}\n")); - if ((!dev_wlc_intvar_get_reg(dev, "btc_params", 50, &saved_reg50)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 51, &saved_reg51)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 64, &saved_reg64)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 65, &saved_reg65)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 71, &saved_reg71))) { - saved_status = TRUE; - WL_TRACE(("%s saved bt_params[50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - __FUNCTION__, saved_reg50, saved_reg51, - saved_reg64, saved_reg65, saved_reg71)); - } else { - WL_ERR((":%s: save btc_params failed\n", - __FUNCTION__)); - saved_status = FALSE; - return -1; - } - - WL_TRACE(("override with [50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - *(u32 *)(buf_reg50va_dhcp_on+4), - *(u32 *)(buf_reg51va_dhcp_on+4), - *(u32 *)(buf_reg64va_dhcp_on+4), - *(u32 *)(buf_reg65va_dhcp_on+4), - *(u32 *)(buf_reg71va_dhcp_on+4))); - - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg50va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg51va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg64va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg65va_dhcp_on[0], 8); - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg71va_dhcp_on[0], 8); - - saved_status = TRUE; - } else if (saved_status) { - /* restore previously saved bt params */ - WL_TRACE(("Do new SCO/eSCO coex algo {save &" - "override}\n")); - - regaddr = 50; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg50); - regaddr = 51; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg51); - regaddr = 64; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg64); - regaddr = 65; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg65); - regaddr = 71; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg71); - - WL_TRACE(("restore bt_params[50,51,64,65,71]:" - "0x%x 0x%x 0x%x 0x%x 0x%x\n", - saved_reg50, saved_reg51, saved_reg64, - saved_reg65, saved_reg71)); - - saved_status = FALSE; - } else { - WL_ERR((":%s att to restore not saved BTCOEX params\n", - __FUNCTION__)); - return -1; - } - return 0; -} -#endif /* BT_DHCP_eSCO_FIX */ - -static void -wl_cfg80211_bt_setflag(struct net_device *dev, bool set) -{ -#if defined(BT_DHCP_USE_FLAGS) - char buf_flag7_dhcp_on[8] = { 7, 00, 00, 00, 0x1, 0x0, 0x00, 0x00 }; - char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; -#endif - - -#if defined(BT_DHCP_eSCO_FIX) - /* set = 1, save & turn on 0 - off & restore prev settings */ - set_btc_esco_params(dev, set); -#endif - -#if defined(BT_DHCP_USE_FLAGS) - WL_TRACE(("WI-FI priority boost via bt flags, set:%d\n", set)); - if (set == TRUE) - /* Forcing bt_flag7 */ - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_dhcp_on[0], - sizeof(buf_flag7_dhcp_on)); - else - /* Restoring default bt flag7 */ - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_default[0], - sizeof(buf_flag7_default)); -#endif -} - -static void wl_cfg80211_bt_timerfunc(ulong data) -{ - struct btcoex_info *bt_local = (struct btcoex_info *)data; - WL_TRACE(("%s\n", __FUNCTION__)); - bt_local->timer_on = 0; - schedule_work(&bt_local->work); -} - -static void wl_cfg80211_bt_handler(struct work_struct *work) -{ - struct btcoex_info *btcx_inf; - - btcx_inf = container_of(work, struct btcoex_info, work); - - if (btcx_inf->timer_on) { - btcx_inf->timer_on = 0; - del_timer_sync(&btcx_inf->timer); - } - - switch (btcx_inf->bt_state) { - case BT_DHCP_START: - /* DHCP started - * provide OPPORTUNITY window to get DHCP address - */ - WL_TRACE(("%s bt_dhcp stm: started \n", - __FUNCTION__)); - btcx_inf->bt_state = BT_DHCP_OPPR_WIN; - mod_timer(&btcx_inf->timer, - jiffies + BT_DHCP_OPPR_WIN_TIME*HZ/1000); - btcx_inf->timer_on = 1; - break; - - case BT_DHCP_OPPR_WIN: - if (btcx_inf->dhcp_done) { - WL_TRACE(("%s DHCP Done before T1 expiration\n", - __FUNCTION__)); - goto btc_coex_idle; - } - - /* DHCP is not over yet, start lowering BT priority - * enforce btc_params + flags if necessary - */ - WL_TRACE(("%s DHCP T1:%d expired\n", __FUNCTION__, - BT_DHCP_OPPR_WIN_TIME)); - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, TRUE); - btcx_inf->bt_state = BT_DHCP_FLAG_FORCE_TIMEOUT; - mod_timer(&btcx_inf->timer, - jiffies + BT_DHCP_FLAG_FORCE_TIME*HZ/1000); - btcx_inf->timer_on = 1; - break; - - case BT_DHCP_FLAG_FORCE_TIMEOUT: - if (btcx_inf->dhcp_done) { - WL_TRACE(("%s DHCP Done before T2 expiration\n", - __FUNCTION__)); - } else { - /* Noo dhcp during T1+T2, restore BT priority */ - WL_TRACE(("%s DHCP wait interval T2:%d" - "msec expired\n", __FUNCTION__, - BT_DHCP_FLAG_FORCE_TIME)); - } - - /* Restoring default bt priority */ - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); -btc_coex_idle: - btcx_inf->bt_state = BT_DHCP_IDLE; - btcx_inf->timer_on = 0; - break; - - default: - WL_ERR(("%s error g_status=%d !!!\n", __FUNCTION__, - btcx_inf->bt_state)); - if (btcx_inf->dev) - wl_cfg80211_bt_setflag(btcx_inf->dev, FALSE); - btcx_inf->bt_state = BT_DHCP_IDLE; - btcx_inf->timer_on = 0; - break; - } - - net_os_wake_unlock(btcx_inf->dev); -} - -int wl_cfg80211_btcoex_init(struct wl_priv *wl) -{ - struct btcoex_info *btco_inf = NULL; - - btco_inf = kmalloc(sizeof(struct btcoex_info), GFP_KERNEL); - if (!btco_inf) - return -ENOMEM; - - btco_inf->bt_state = BT_DHCP_IDLE; - btco_inf->ts_dhcp_start = 0; - btco_inf->ts_dhcp_ok = 0; - /* Set up timer for BT */ - btco_inf->timer_ms = 10; - init_timer(&btco_inf->timer); - btco_inf->timer.data = (ulong)btco_inf; - btco_inf->timer.function = wl_cfg80211_bt_timerfunc; - - btco_inf->dev = wl->wdev->netdev; - - INIT_WORK(&btco_inf->work, wl_cfg80211_bt_handler); - - wl->btcoex_info = btco_inf; - return 0; -} - -void wl_cfg80211_btcoex_deinit(struct wl_priv *wl) -{ - if (!wl->btcoex_info) - return; - - if (!wl->btcoex_info->timer_on) { - wl->btcoex_info->timer_on = 0; - del_timer_sync(&wl->btcoex_info->timer); - } - - cancel_work_sync(&wl->btcoex_info->work); - - kfree(wl->btcoex_info); - wl->btcoex_info = NULL; -} -#endif /* COEX_DHCP */ - -int wl_cfg80211_set_btcoex_dhcp(struct net_device *dev, char *command) -{ - - struct wl_priv *wl = wlcfg_drv_priv; - char powermode_val = 0; - char buf_reg66va_dhcp_on[8] = { 66, 00, 00, 00, 0x10, 0x27, 0x00, 0x00 }; - char buf_reg41va_dhcp_on[8] = { 41, 00, 00, 00, 0x33, 0x00, 0x00, 0x00 }; - char buf_reg68va_dhcp_on[8] = { 68, 00, 00, 00, 0x90, 0x01, 0x00, 0x00 }; - - uint32 regaddr; - static uint32 saved_reg66; - static uint32 saved_reg41; - static uint32 saved_reg68; - static bool saved_status = FALSE; - -#ifdef COEX_DHCP - char buf_flag7_default[8] = { 7, 00, 00, 00, 0x0, 0x00, 0x00, 0x00}; - struct btcoex_info *btco_inf = wl->btcoex_info; -#endif /* COEX_DHCP */ - -#ifdef PKT_FILTER_SUPPORT - dhd_pub_t *dhd = (dhd_pub_t *)(wl->pub); - int i; -#endif - - /* Figure out powermode 1 or o command */ - strncpy((char *)&powermode_val, command + strlen("BTCOEXMODE") +1, 1); - WL_ERR(("%s: DHCP session Enter\n", __FUNCTION__)); - - if (strnicmp((char *)&powermode_val, "1", strlen("1")) == 0) { - - WL_ERR(("%s: DHCP session starts\n", __FUNCTION__)); - -#ifdef PKT_FILTER_SUPPORT - dhd->dhcp_in_progress = 1; - - /* Disable packet filtering */ - if (dhd_pkt_filter_enable && dhd->early_suspended) { - WL_ERR(("DHCP in progressing , disable packet filter!!!\n")); - for (i = 0; i < dhd->pktfilter_count; i++) { - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - 0, dhd_master_mode); - } - } -#endif - - /* Retrieve and saved orig regs value */ - if ((saved_status == FALSE) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 66, &saved_reg66)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 41, &saved_reg41)) && - (!dev_wlc_intvar_get_reg(dev, "btc_params", 68, &saved_reg68))) { - saved_status = TRUE; - WL_TRACE(("Saved 0x%x 0x%x 0x%x\n", - saved_reg66, saved_reg41, saved_reg68)); - - /* Disable PM mode during dhpc session */ - - /* Disable PM mode during dhpc session */ -#ifdef COEX_DHCP - /* Start BT timer only for SCO connection */ - if (btcoex_is_sco_active(dev)) { - /* btc_params 66 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg66va_dhcp_on[0], - sizeof(buf_reg66va_dhcp_on)); - /* btc_params 41 0x33 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg41va_dhcp_on[0], - sizeof(buf_reg41va_dhcp_on)); - /* btc_params 68 0x190 */ - dev_wlc_bufvar_set(dev, "btc_params", - (char *)&buf_reg68va_dhcp_on[0], - sizeof(buf_reg68va_dhcp_on)); - saved_status = TRUE; - - btco_inf->bt_state = BT_DHCP_START; - btco_inf->timer_on = 1; - mod_timer(&btco_inf->timer, btco_inf->timer.expires); - WL_TRACE(("%s enable BT DHCP Timer\n", - __FUNCTION__)); - } -#endif /* COEX_DHCP */ - } - else if (saved_status == TRUE) { - WL_ERR(("%s was called w/o DHCP OFF. Continue\n", __FUNCTION__)); - } - } - else if (strnicmp((char *)&powermode_val, "2", strlen("2")) == 0) { - -#ifdef PKT_FILTER_SUPPORT - dhd->dhcp_in_progress = 0; - WL_ERR(("%s: DHCP is complete \n", __FUNCTION__)); - - /* Enable packet filtering */ - if (dhd_pkt_filter_enable && dhd->early_suspended) { - WL_ERR(("DHCP is complete , enable packet filter!!!\n")); - for (i = 0; i < dhd->pktfilter_count; i++) { - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - 1, dhd_master_mode); - } - } -#endif - - /* Restoring PM mode */ - -#ifdef COEX_DHCP - /* Stop any bt timer because DHCP session is done */ - WL_TRACE(("%s disable BT DHCP Timer\n", __FUNCTION__)); - if (btco_inf->timer_on) { - btco_inf->timer_on = 0; - del_timer_sync(&btco_inf->timer); - - if (btco_inf->bt_state != BT_DHCP_IDLE) { - /* need to restore original btc flags & extra btc params */ - WL_TRACE(("%s bt->bt_state:%d\n", - __FUNCTION__, btco_inf->bt_state)); - /* wake up btcoex thread to restore btlags+params */ - schedule_work(&btco_inf->work); - } - } - - /* Restoring btc_flag paramter anyway */ - if (saved_status == TRUE) - dev_wlc_bufvar_set(dev, "btc_flags", - (char *)&buf_flag7_default[0], sizeof(buf_flag7_default)); -#endif /* COEX_DHCP */ - - /* Restore original values */ - if (saved_status == TRUE) { - regaddr = 66; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg66); - regaddr = 41; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg41); - regaddr = 68; - dev_wlc_intvar_set_reg(dev, "btc_params", - (char *)®addr, (char *)&saved_reg68); - - WL_TRACE(("restore regs {66,41,68} <- 0x%x 0x%x 0x%x\n", - saved_reg66, saved_reg41, saved_reg68)); - } - saved_status = FALSE; - - } - else { - WL_ERR(("%s Unkwown yet power setting, ignored\n", - __FUNCTION__)); - } - - snprintf(command, 3, "OK"); - - return (strlen("OK")); -} diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_cfg80211.h b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_cfg80211.h deleted file mode 100644 index f4374f1..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_cfg80211.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Linux cfg80211 driver - Dongle Host Driver (DHD) related - * - * Copyright (C) 1999-2011, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: wl_cfg80211.c,v 1.1.4.1.2.14 2011/02/09 01:40:07 Exp $ - */ - - -#ifndef __DHD_CFG80211__ -#define __DHD_CFG80211__ - -#include <wl_cfg80211.h> -#include <wl_cfgp2p.h> - -s32 dhd_cfg80211_init(struct wl_priv *wl); -s32 dhd_cfg80211_deinit(struct wl_priv *wl); -s32 dhd_cfg80211_down(struct wl_priv *wl); -s32 dhd_config_dongle(struct wl_priv *wl, bool need_lock); - -int wl_cfg80211_btcoex_init(struct wl_priv *wl); -void wl_cfg80211_btcoex_deinit(struct wl_priv *wl); - -#endif /* __DHD_CFG80211__ */ diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_common.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_common.c deleted file mode 100644 index 9fda3c1..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_common.c +++ /dev/null @@ -1,2344 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), common DHD core. - * - * Copyright (C) 1999-2012, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_common.c 304622 2011-12-22 19:51:18Z $ - */ -#include <typedefs.h> -#include <osl.h> - -#include <epivers.h> -#include <bcmutils.h> - -#include <bcmendian.h> -#include <dngl_stats.h> -#include <wlioctl.h> -#include <dhd.h> - -#include <proto/bcmevent.h> - -#include <dhd_bus.h> -#include <dhd_proto.h> -#include <dhd_dbg.h> -#include <msgtrace.h> - -#ifdef WL_CFG80211 -#include <wl_cfg80211.h> -#endif -#ifdef WLBTAMP -#include <proto/bt_amp_hci.h> -#include <dhd_bta.h> -#endif -#ifdef SET_RANDOM_MAC_SOFTAP -#include <linux/random.h> -#include <linux/jiffies.h> -#endif - -#define htod32(i) i -#define htod16(i) i -#define dtoh32(i) i -#define dtoh16(i) i -#define htodchanspec(i) i -#define dtohchanspec(i) i - -#ifdef PROP_TXSTATUS -#include <wlfc_proto.h> -#include <dhd_wlfc.h> -#endif - - -#ifdef WLMEDIA_HTSF -extern void htsf_update(struct dhd_info *dhd, void *data); -#endif -int dhd_msg_level = DHD_ERROR_VAL; - - -#include <wl_iw.h> - -char fw_path[MOD_PARAM_PATHLEN]; -char nv_path[MOD_PARAM_PATHLEN]; - -#ifdef SOFTAP -char fw_path2[MOD_PARAM_PATHLEN]; -extern bool softap_enabled; -#endif - -/* Last connection success/failure status */ -uint32 dhd_conn_event; -uint32 dhd_conn_status; -uint32 dhd_conn_reason; - -extern int dhd_iscan_request(void * dhdp, uint16 action); -extern void dhd_ind_scan_confirm(void *h, bool status); -extern int dhd_iscan_in_progress(void *h); -void dhd_iscan_lock(void); -void dhd_iscan_unlock(void); -extern int dhd_change_mtu(dhd_pub_t *dhd, int new_mtu, int ifidx); -extern bool dhd_concurrent_fw(dhd_pub_t *dhd); -bool ap_cfg_running = FALSE; -bool ap_fw_loaded = FALSE; - - -#ifdef DHD_DEBUG -const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR "\nCompiled on " - __DATE__ " at " __TIME__; -#else -const char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR; -#endif - -void dhd_set_timer(void *bus, uint wdtick); - -/* IOVar table */ -enum { - IOV_VERSION = 1, - IOV_MSGLEVEL, - IOV_BCMERRORSTR, - IOV_BCMERROR, - IOV_WDTICK, - IOV_DUMP, - IOV_CLEARCOUNTS, - IOV_LOGDUMP, - IOV_LOGCAL, - IOV_LOGSTAMP, - IOV_GPIOOB, - IOV_IOCTLTIMEOUT, -#ifdef WLBTAMP - IOV_HCI_CMD, /* HCI command */ - IOV_HCI_ACL_DATA, /* HCI data packet */ -#endif -#if defined(DHD_DEBUG) - IOV_CONS, - IOV_DCONSOLE_POLL, -#endif /* defined(DHD_DEBUG) */ -#ifdef PROP_TXSTATUS - IOV_PROPTXSTATUS_ENABLE, - IOV_PROPTXSTATUS_MODE, -#endif - IOV_BUS_TYPE, -#ifdef WLMEDIA_HTSF - IOV_WLPKTDLYSTAT_SZ, -#endif - IOV_CHANGEMTU, - IOV_HOSTREORDER_FLOWS, - IOV_LAST -}; - -const bcm_iovar_t dhd_iovars[] = { - {"version", IOV_VERSION, 0, IOVT_BUFFER, sizeof(dhd_version) }, -#ifdef DHD_DEBUG - {"msglevel", IOV_MSGLEVEL, 0, IOVT_UINT32, 0 }, -#endif /* DHD_DEBUG */ - {"bcmerrorstr", IOV_BCMERRORSTR, 0, IOVT_BUFFER, BCME_STRLEN }, - {"bcmerror", IOV_BCMERROR, 0, IOVT_INT8, 0 }, - {"wdtick", IOV_WDTICK, 0, IOVT_UINT32, 0 }, - {"dump", IOV_DUMP, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, -#ifdef DHD_DEBUG - {"cons", IOV_CONS, 0, IOVT_BUFFER, 0 }, - {"dconpoll", IOV_DCONSOLE_POLL, 0, IOVT_UINT32, 0 }, -#endif - {"clearcounts", IOV_CLEARCOUNTS, 0, IOVT_VOID, 0 }, - {"gpioob", IOV_GPIOOB, 0, IOVT_UINT32, 0 }, - {"ioctl_timeout", IOV_IOCTLTIMEOUT, 0, IOVT_UINT32, 0 }, -#ifdef WLBTAMP - {"HCI_cmd", IOV_HCI_CMD, 0, IOVT_BUFFER, 0}, - {"HCI_ACL_data", IOV_HCI_ACL_DATA, 0, IOVT_BUFFER, 0}, -#endif -#ifdef PROP_TXSTATUS - {"proptx", IOV_PROPTXSTATUS_ENABLE, 0, IOVT_UINT32, 0 }, - /* - set the proptxtstatus operation mode: - 0 - Do not do any proptxtstatus flow control - 1 - Use implied credit from a packet status - 2 - Use explicit credit - */ - {"ptxmode", IOV_PROPTXSTATUS_MODE, 0, IOVT_UINT32, 0 }, -#endif - {"bustype", IOV_BUS_TYPE, 0, IOVT_UINT32, 0}, -#ifdef WLMEDIA_HTSF - {"pktdlystatsz", IOV_WLPKTDLYSTAT_SZ, 0, IOVT_UINT8, 0 }, -#endif - {"changemtu", IOV_CHANGEMTU, 0, IOVT_UINT32, 0 }, - {"host_reorder_flows", IOV_HOSTREORDER_FLOWS, 0, IOVT_BUFFER, - (WLHOST_REORDERDATA_MAXFLOWS + 1) }, - {NULL, 0, 0, 0, 0 } -}; - -void -dhd_common_init(osl_t *osh) -{ - - /* Init global variables at run-time, not as part of the declaration. - * This is required to support init/de-init of the driver. Initialization - * of globals as part of the declaration results in non-deterministic - * behavior since the value of the globals may be different on the - * first time that the driver is initialized vs subsequent initializations. - */ - /* Allocate private bus interface state */ - -#ifdef CONFIG_BCMDHD_FW_PATH - bcm_strncpy_s(fw_path, sizeof(fw_path), CONFIG_BCMDHD_FW_PATH, MOD_PARAM_PATHLEN-1); -#else /* CONFIG_BCMDHD_FW_PATH */ - fw_path[0] = '\0'; -#endif /* CONFIG_BCMDHD_FW_PATH */ -#ifdef CONFIG_BCMDHD_NVRAM_PATH - bcm_strncpy_s(nv_path, sizeof(nv_path), CONFIG_BCMDHD_NVRAM_PATH, MOD_PARAM_PATHLEN-1); -#else /* CONFIG_BCMDHD_NVRAM_PATH */ - nv_path[0] = '\0'; -#endif /* CONFIG_BCMDHD_NVRAM_PATH */ -#ifdef SOFTAP - fw_path2[0] = '\0'; -#endif - -} - -static int -dhd_dump(dhd_pub_t *dhdp, char *buf, int buflen) -{ - char eabuf[ETHER_ADDR_STR_LEN]; - - struct bcmstrbuf b; - struct bcmstrbuf *strbuf = &b; - - bcm_binit(strbuf, buf, buflen); - - /* Base DHD info */ - bcm_bprintf(strbuf, "%s\n", dhd_version); - bcm_bprintf(strbuf, "\n"); - bcm_bprintf(strbuf, "pub.up %d pub.txoff %d pub.busstate %d\n", - dhdp->up, dhdp->txoff, dhdp->busstate); - bcm_bprintf(strbuf, "pub.hdrlen %d pub.maxctl %d pub.rxsz %d\n", - dhdp->hdrlen, dhdp->maxctl, dhdp->rxsz); - bcm_bprintf(strbuf, "pub.iswl %d pub.drv_version %ld pub.mac %s\n", - dhdp->iswl, dhdp->drv_version, bcm_ether_ntoa(&dhdp->mac, eabuf)); - bcm_bprintf(strbuf, "pub.bcmerror %d tickcnt %d\n", dhdp->bcmerror, dhdp->tickcnt); - - bcm_bprintf(strbuf, "dongle stats:\n"); - bcm_bprintf(strbuf, "tx_packets %ld tx_bytes %ld tx_errors %ld tx_dropped %ld\n", - dhdp->dstats.tx_packets, dhdp->dstats.tx_bytes, - dhdp->dstats.tx_errors, dhdp->dstats.tx_dropped); - bcm_bprintf(strbuf, "rx_packets %ld rx_bytes %ld rx_errors %ld rx_dropped %ld\n", - dhdp->dstats.rx_packets, dhdp->dstats.rx_bytes, - dhdp->dstats.rx_errors, dhdp->dstats.rx_dropped); - bcm_bprintf(strbuf, "multicast %ld\n", dhdp->dstats.multicast); - - bcm_bprintf(strbuf, "bus stats:\n"); - bcm_bprintf(strbuf, "tx_packets %ld tx_multicast %ld tx_errors %ld\n", - dhdp->tx_packets, dhdp->tx_multicast, dhdp->tx_errors); - bcm_bprintf(strbuf, "tx_ctlpkts %ld tx_ctlerrs %ld\n", - dhdp->tx_ctlpkts, dhdp->tx_ctlerrs); - bcm_bprintf(strbuf, "rx_packets %ld rx_multicast %ld rx_errors %ld \n", - dhdp->rx_packets, dhdp->rx_multicast, dhdp->rx_errors); - bcm_bprintf(strbuf, "rx_ctlpkts %ld rx_ctlerrs %ld rx_dropped %ld\n", - dhdp->rx_ctlpkts, dhdp->rx_ctlerrs, dhdp->rx_dropped); - bcm_bprintf(strbuf, "rx_readahead_cnt %ld tx_realloc %ld\n", - dhdp->rx_readahead_cnt, dhdp->tx_realloc); - bcm_bprintf(strbuf, "\n"); - - /* Add any prot info */ - dhd_prot_dump(dhdp, strbuf); - bcm_bprintf(strbuf, "\n"); - - /* Add any bus info */ - dhd_bus_dump(dhdp, strbuf); - - return (!strbuf->size ? BCME_BUFTOOSHORT : 0); -} - -int -dhd_wl_ioctl_cmd(dhd_pub_t *dhd_pub, int cmd, void *arg, int len, uint8 set, int ifindex) -{ - wl_ioctl_t ioc; - - ioc.cmd = cmd; - ioc.buf = arg; - ioc.len = len; - ioc.set = set; - - return dhd_wl_ioctl(dhd_pub, ifindex, &ioc, arg, len); -} - - -int -dhd_wl_ioctl(dhd_pub_t *dhd_pub, int ifindex, wl_ioctl_t *ioc, void *buf, int len) -{ - int ret; - - dhd_os_proto_block(dhd_pub); - - ret = dhd_prot_ioctl(dhd_pub, ifindex, ioc, buf, len); - if (!ret || ret == -ETIMEDOUT) { - /* Send hang event only if dhd_open() was success */ - if (dhd_pub->up) - dhd_os_check_hang(dhd_pub, ifindex, ret); - } - - dhd_os_proto_unblock(dhd_pub); -#ifdef CUSTOMER_HW_SAMSUNG - if (ret < 0) { - if (ioc->cmd == WLC_GET_VAR) - DHD_ERROR(("%s: WLC_GET_VAR: %s, ret = %d\n", - __FUNCTION__, (char *)ioc->buf, ret)); - else if (ioc->cmd == WLC_SET_VAR) - DHD_ERROR(("%s: WLC_SET_VAR: %s, ret = %d\n", - __FUNCTION__, (char *)ioc->buf, ret)); - else - DHD_ERROR(("%s: WLC_IOCTL: cmd: %d, ret = %d\n", - __FUNCTION__, ioc->cmd, ret)); - } -#endif /* CUSTOMER_HW_SAMSUNG */ - - return ret; -} - -static int -dhd_doiovar(dhd_pub_t *dhd_pub, const bcm_iovar_t *vi, uint32 actionid, const char *name, - void *params, int plen, void *arg, int len, int val_size) -{ - int bcmerror = 0; - int32 int_val = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_TRACE(("%s: actionid = %d; name %s\n", __FUNCTION__, actionid, name)); - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) - goto exit; - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - switch (actionid) { - case IOV_GVAL(IOV_VERSION): - /* Need to have checked buffer length */ - bcm_strncpy_s((char*)arg, len, dhd_version, len); - break; - - case IOV_GVAL(IOV_MSGLEVEL): - int_val = (int32)dhd_msg_level; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_MSGLEVEL): - dhd_msg_level = int_val; - break; - case IOV_GVAL(IOV_BCMERRORSTR): - bcm_strncpy_s((char *)arg, len, bcmerrorstr(dhd_pub->bcmerror), BCME_STRLEN); - ((char *)arg)[BCME_STRLEN - 1] = 0x00; - break; - - case IOV_GVAL(IOV_BCMERROR): - int_val = (int32)dhd_pub->bcmerror; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_WDTICK): - int_val = (int32)dhd_watchdog_ms; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_WDTICK): - if (!dhd_pub->up) { - bcmerror = BCME_NOTUP; - break; - } - dhd_os_wd_timer(dhd_pub, (uint)int_val); - break; - - case IOV_GVAL(IOV_DUMP): - bcmerror = dhd_dump(dhd_pub, arg, len); - break; - -#ifdef DHD_DEBUG - case IOV_GVAL(IOV_DCONSOLE_POLL): - int_val = (int32)dhd_console_ms; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DCONSOLE_POLL): - dhd_console_ms = (uint)int_val; - break; - - case IOV_SVAL(IOV_CONS): - if (len > 0) - bcmerror = dhd_bus_console_in(dhd_pub, arg, len - 1); - break; -#endif /* DHD_DEBUG */ - - case IOV_SVAL(IOV_CLEARCOUNTS): - dhd_pub->tx_packets = dhd_pub->rx_packets = 0; - dhd_pub->tx_errors = dhd_pub->rx_errors = 0; - dhd_pub->tx_ctlpkts = dhd_pub->rx_ctlpkts = 0; - dhd_pub->tx_ctlerrs = dhd_pub->rx_ctlerrs = 0; - dhd_pub->rx_dropped = 0; - dhd_pub->rx_readahead_cnt = 0; - dhd_pub->tx_realloc = 0; - dhd_pub->wd_dpc_sched = 0; - memset(&dhd_pub->dstats, 0, sizeof(dhd_pub->dstats)); - dhd_bus_clearcounts(dhd_pub); -#ifdef PROP_TXSTATUS - /* clear proptxstatus related counters */ - if (dhd_pub->wlfc_state) { - athost_wl_status_info_t *wlfc = - (athost_wl_status_info_t*)dhd_pub->wlfc_state; - wlfc_hanger_t* hanger; - - memset(&wlfc->stats, 0, sizeof(athost_wl_stat_counters_t)); - - hanger = (wlfc_hanger_t*)wlfc->hanger; - hanger->pushed = 0; - hanger->popped = 0; - hanger->failed_slotfind = 0; - hanger->failed_to_pop = 0; - hanger->failed_to_push = 0; - } -#endif /* PROP_TXSTATUS */ - break; - - - case IOV_GVAL(IOV_IOCTLTIMEOUT): { - int_val = (int32)dhd_os_get_ioctl_resp_timeout(); - bcopy(&int_val, arg, sizeof(int_val)); - break; - } - - case IOV_SVAL(IOV_IOCTLTIMEOUT): { - if (int_val <= 0) - bcmerror = BCME_BADARG; - else - dhd_os_set_ioctl_resp_timeout((unsigned int)int_val); - break; - } - -#ifdef WLBTAMP - case IOV_SVAL(IOV_HCI_CMD): { - amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)arg; - - /* sanity check: command preamble present */ - if (len < HCI_CMD_PREAMBLE_SIZE) - return BCME_BUFTOOSHORT; - - /* sanity check: command parameters are present */ - if (len < (int)(HCI_CMD_PREAMBLE_SIZE + cmd->plen)) - return BCME_BUFTOOSHORT; - - dhd_bta_docmd(dhd_pub, cmd, len); - break; - } - - case IOV_SVAL(IOV_HCI_ACL_DATA): { - amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *)arg; - - /* sanity check: HCI header present */ - if (len < HCI_ACL_DATA_PREAMBLE_SIZE) - return BCME_BUFTOOSHORT; - - /* sanity check: ACL data is present */ - if (len < (int)(HCI_ACL_DATA_PREAMBLE_SIZE + ACL_data->dlen)) - return BCME_BUFTOOSHORT; - - dhd_bta_tx_hcidata(dhd_pub, ACL_data, len); - break; - } -#endif /* WLBTAMP */ - -#ifdef PROP_TXSTATUS - case IOV_GVAL(IOV_PROPTXSTATUS_ENABLE): - int_val = dhd_pub->wlfc_enabled? 1 : 0; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_PROPTXSTATUS_ENABLE): - dhd_pub->wlfc_enabled = int_val? 1 : 0; - break; - - case IOV_GVAL(IOV_PROPTXSTATUS_MODE): { - athost_wl_status_info_t *wlfc = - (athost_wl_status_info_t*)dhd_pub->wlfc_state; - int_val = dhd_pub->wlfc_state ? (int32)wlfc->proptxstatus_mode : 0; - bcopy(&int_val, arg, val_size); - break; - } - - case IOV_SVAL(IOV_PROPTXSTATUS_MODE): - if (dhd_pub->wlfc_state) { - athost_wl_status_info_t *wlfc = - (athost_wl_status_info_t*)dhd_pub->wlfc_state; - wlfc->proptxstatus_mode = int_val & 0xff; - } - break; -#endif /* PROP_TXSTATUS */ - - case IOV_GVAL(IOV_BUS_TYPE): - /* The dhd application queries the driver to check if its usb or sdio. */ -#ifdef BCMDHDUSB - int_val = BUS_TYPE_USB; -#endif - int_val = BUS_TYPE_SDIO; - bcopy(&int_val, arg, val_size); - break; - - -#ifdef WLMEDIA_HTSF - case IOV_GVAL(IOV_WLPKTDLYSTAT_SZ): - int_val = dhd_pub->htsfdlystat_sz; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_WLPKTDLYSTAT_SZ): - dhd_pub->htsfdlystat_sz = int_val & 0xff; - printf("Setting tsfdlystat_sz:%d\n", dhd_pub->htsfdlystat_sz); - break; -#endif - case IOV_SVAL(IOV_CHANGEMTU): - int_val &= 0xffff; - bcmerror = dhd_change_mtu(dhd_pub, int_val, 0); - break; - - case IOV_GVAL(IOV_HOSTREORDER_FLOWS): - { - uint i = 0; - uint8 *ptr = (uint8 *)arg; - uint8 count = 0; - - ptr++; - for (i = 0; i < WLHOST_REORDERDATA_MAXFLOWS; i++) { - if (dhd_pub->reorder_bufs[i] != NULL) { - *ptr = dhd_pub->reorder_bufs[i]->flow_id; - ptr++; - count++; - } - } - ptr = (uint8 *)arg; - *ptr = count; - break; - } - - default: - bcmerror = BCME_UNSUPPORTED; - break; - } - -exit: - DHD_TRACE(("%s: actionid %d, bcmerror %d\n", __FUNCTION__, actionid, bcmerror)); - return bcmerror; -} - -/* Store the status of a connection attempt for later retrieval by an iovar */ -void -dhd_store_conn_status(uint32 event, uint32 status, uint32 reason) -{ - /* Do not overwrite a WLC_E_PRUNE with a WLC_E_SET_SSID - * because an encryption/rsn mismatch results in both events, and - * the important information is in the WLC_E_PRUNE. - */ - if (!(event == WLC_E_SET_SSID && status == WLC_E_STATUS_FAIL && - dhd_conn_event == WLC_E_PRUNE)) { - dhd_conn_event = event; - dhd_conn_status = status; - dhd_conn_reason = reason; - } -} - -bool -dhd_prec_enq(dhd_pub_t *dhdp, struct pktq *q, void *pkt, int prec) -{ - void *p; - int eprec = -1; /* precedence to evict from */ - bool discard_oldest; - - /* Fast case, precedence queue is not full and we are also not - * exceeding total queue length - */ - if (!pktq_pfull(q, prec) && !pktq_full(q)) { - pktq_penq(q, prec, pkt); - return TRUE; - } - - /* Determine precedence from which to evict packet, if any */ - if (pktq_pfull(q, prec)) - eprec = prec; - else if (pktq_full(q)) { - p = pktq_peek_tail(q, &eprec); -// ASSERT(p); - if (eprec > prec || eprec < 0) - return FALSE; - } - - /* Evict if needed */ - if (eprec >= 0) { - /* Detect queueing to unconfigured precedence */ - ASSERT(!pktq_pempty(q, eprec)); - discard_oldest = AC_BITMAP_TST(dhdp->wme_dp, eprec); - if (eprec == prec && !discard_oldest) - return FALSE; /* refuse newer (incoming) packet */ - /* Evict packet according to discard policy */ - p = discard_oldest ? pktq_pdeq(q, eprec) : pktq_pdeq_tail(q, eprec); - ASSERT(p); - - PKTFREE(dhdp->osh, p, TRUE); - } - - /* Enqueue */ - p = pktq_penq(q, prec, pkt); -// ASSERT(p); - - return TRUE; -} - -static int -dhd_iovar_op(dhd_pub_t *dhd_pub, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - int bcmerror = 0; - int val_size; - const bcm_iovar_t *vi = NULL; - uint32 actionid; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(name); - ASSERT(len >= 0); - - /* Get MUST have return space */ - ASSERT(set || (arg && len)); - - /* Set does NOT take qualifiers */ - ASSERT(!set || (!params && !plen)); - - if ((vi = bcm_iovar_lookup(dhd_iovars, name)) == NULL) { - bcmerror = BCME_UNSUPPORTED; - goto exit; - } - - DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, - name, (set ? "set" : "get"), len, plen)); - - /* set up 'params' pointer in case this is a set command so that - * the convenience int and bool code can be common to set and get - */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - /* all other types are integer sized */ - val_size = sizeof(int); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - - bcmerror = dhd_doiovar(dhd_pub, vi, actionid, name, params, plen, arg, len, val_size); - -exit: - return bcmerror; -} - -int -dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen) -{ - int bcmerror = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!buf) { - return BCME_BADARG; - } - - switch (ioc->cmd) { - case DHD_GET_MAGIC: - if (buflen < sizeof(int)) - bcmerror = BCME_BUFTOOSHORT; - else - *(int*)buf = DHD_IOCTL_MAGIC; - break; - - case DHD_GET_VERSION: - if (buflen < sizeof(int)) - bcmerror = -BCME_BUFTOOSHORT; - else - *(int*)buf = DHD_IOCTL_VERSION; - break; - - case DHD_GET_VAR: - case DHD_SET_VAR: { - char *arg; - uint arglen; - - /* scan past the name to any arguments */ - for (arg = buf, arglen = buflen; *arg && arglen; arg++, arglen--) - ; - - if (*arg) { - bcmerror = BCME_BUFTOOSHORT; - break; - } - - /* account for the NUL terminator */ - arg++, arglen--; - - /* call with the appropriate arguments */ - if (ioc->cmd == DHD_GET_VAR) - bcmerror = dhd_iovar_op(dhd_pub, buf, arg, arglen, - buf, buflen, IOV_GET); - else - bcmerror = dhd_iovar_op(dhd_pub, buf, NULL, 0, arg, arglen, IOV_SET); - if (bcmerror != BCME_UNSUPPORTED) - break; - - /* not in generic table, try protocol module */ - if (ioc->cmd == DHD_GET_VAR) - bcmerror = dhd_prot_iovar_op(dhd_pub, buf, arg, - arglen, buf, buflen, IOV_GET); - else - bcmerror = dhd_prot_iovar_op(dhd_pub, buf, - NULL, 0, arg, arglen, IOV_SET); - if (bcmerror != BCME_UNSUPPORTED) - break; - - /* if still not found, try bus module */ - if (ioc->cmd == DHD_GET_VAR) { - bcmerror = dhd_bus_iovar_op(dhd_pub, buf, - arg, arglen, buf, buflen, IOV_GET); - } else { - bcmerror = dhd_bus_iovar_op(dhd_pub, buf, - NULL, 0, arg, arglen, IOV_SET); - } - - break; - } - - default: - bcmerror = BCME_UNSUPPORTED; - } - - return bcmerror; -} - -#ifdef SHOW_EVENTS -static void -wl_show_host_event(wl_event_msg_t *event, void *event_data) -{ - uint i, status, reason; - bool group = FALSE, flush_txq = FALSE, link = FALSE; - const char *auth_str; - const char *event_name; - uchar *buf; - char err_msg[256], eabuf[ETHER_ADDR_STR_LEN]; - uint event_type, flags, auth_type, datalen; - - event_type = ntoh32(event->event_type); - flags = ntoh16(event->flags); - status = ntoh32(event->status); - reason = ntoh32(event->reason); - auth_type = ntoh32(event->auth_type); - datalen = ntoh32(event->datalen); - - /* debug dump of event messages */ - sprintf(eabuf, "%02x:%02x:%02x:%02x:%02x:%02x", - (uchar)event->addr.octet[0]&0xff, - (uchar)event->addr.octet[1]&0xff, - (uchar)event->addr.octet[2]&0xff, - (uchar)event->addr.octet[3]&0xff, - (uchar)event->addr.octet[4]&0xff, - (uchar)event->addr.octet[5]&0xff); - - event_name = "UNKNOWN"; - for (i = 0; i < (uint)bcmevent_names_size; i++) - if (bcmevent_names[i].event == event_type) - event_name = bcmevent_names[i].name; - - if (flags & WLC_EVENT_MSG_LINK) - link = TRUE; - if (flags & WLC_EVENT_MSG_GROUP) - group = TRUE; - if (flags & WLC_EVENT_MSG_FLUSHTXQ) - flush_txq = TRUE; - - switch (event_type) { - case WLC_E_START: - case WLC_E_DEAUTH: - case WLC_E_DISASSOC: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; - - case WLC_E_ASSOC_IND: - case WLC_E_REASSOC_IND: - - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - break; - - case WLC_E_ASSOC: - case WLC_E_REASSOC: - if (status == WLC_E_STATUS_SUCCESS) { - DHD_EVENT(("MACEVENT: %s, MAC %s, SUCCESS\n", event_name, eabuf)); - } else if (status == WLC_E_STATUS_TIMEOUT) { - DHD_EVENT(("MACEVENT: %s, MAC %s, TIMEOUT\n", event_name, eabuf)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_EVENT(("MACEVENT: %s, MAC %s, FAILURE, reason %d\n", - event_name, eabuf, (int)reason)); - } else { - DHD_EVENT(("MACEVENT: %s, MAC %s, unexpected status %d\n", - event_name, eabuf, (int)status)); - } - break; - - case WLC_E_DEAUTH_IND: - case WLC_E_DISASSOC_IND: - DHD_EVENT(("MACEVENT: %s, MAC %s, reason %d\n", event_name, eabuf, (int)reason)); - break; - - case WLC_E_AUTH: - case WLC_E_AUTH_IND: - if (auth_type == DOT11_OPEN_SYSTEM) - auth_str = "Open System"; - else if (auth_type == DOT11_SHARED_KEY) - auth_str = "Shared Key"; - else { - sprintf(err_msg, "AUTH unknown: %d", (int)auth_type); - auth_str = err_msg; - } - if (event_type == WLC_E_AUTH_IND) { - DHD_EVENT(("MACEVENT: %s, MAC %s, %s\n", event_name, eabuf, auth_str)); - } else if (status == WLC_E_STATUS_SUCCESS) { - DHD_EVENT(("MACEVENT: %s, MAC %s, %s, SUCCESS\n", - event_name, eabuf, auth_str)); - } else if (status == WLC_E_STATUS_TIMEOUT) { - DHD_EVENT(("MACEVENT: %s, MAC %s, %s, TIMEOUT\n", - event_name, eabuf, auth_str)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_EVENT(("MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n", - event_name, eabuf, auth_str, (int)reason)); - } - - break; - - case WLC_E_JOIN: - case WLC_E_ROAM: - case WLC_E_SET_SSID: - if (status == WLC_E_STATUS_SUCCESS) { - DHD_EVENT(("MACEVENT: %s, MAC %s\n", event_name, eabuf)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_EVENT(("MACEVENT: %s, failed\n", event_name)); - } else if (status == WLC_E_STATUS_NO_NETWORKS) { - DHD_EVENT(("MACEVENT: %s, no networks found\n", event_name)); - } else { - DHD_EVENT(("MACEVENT: %s, unexpected status %d\n", - event_name, (int)status)); - } - break; - - case WLC_E_BEACON_RX: - if (status == WLC_E_STATUS_SUCCESS) { - DHD_EVENT(("MACEVENT: %s, SUCCESS\n", event_name)); - } else if (status == WLC_E_STATUS_FAIL) { - DHD_EVENT(("MACEVENT: %s, FAIL\n", event_name)); - } else { - DHD_EVENT(("MACEVENT: %s, status %d\n", event_name, status)); - } - break; - - case WLC_E_LINK: - DHD_EVENT(("MACEVENT: %s %s\n", event_name, link?"UP":"DOWN")); - break; - - case WLC_E_MIC_ERROR: - DHD_EVENT(("MACEVENT: %s, MAC %s, Group %d, Flush %d\n", - event_name, eabuf, group, flush_txq)); - break; - - case WLC_E_ICV_ERROR: - case WLC_E_UNICAST_DECODE_ERROR: - case WLC_E_MULTICAST_DECODE_ERROR: - DHD_EVENT(("MACEVENT: %s, MAC %s\n", - event_name, eabuf)); - break; - - case WLC_E_TXFAIL: - DHD_EVENT(("MACEVENT: %s, RA %s\n", event_name, eabuf)); - break; - - case WLC_E_SCAN_COMPLETE: - case WLC_E_ASSOC_REQ_IE: - case WLC_E_ASSOC_RESP_IE: - case WLC_E_PMKID_CACHE: - DHD_EVENT(("MACEVENT: %s\n", event_name)); - break; - - case WLC_E_PFN_NET_FOUND: - case WLC_E_PFN_NET_LOST: - case WLC_E_PFN_SCAN_COMPLETE: - case WLC_E_PFN_SCAN_NONE: - case WLC_E_PFN_SCAN_ALLGONE: - DHD_EVENT(("PNOEVENT: %s\n", event_name)); - break; - - case WLC_E_PSK_SUP: - case WLC_E_PRUNE: - DHD_EVENT(("MACEVENT: %s, status %d, reason %d\n", - event_name, (int)status, (int)reason)); - break; - -#ifdef WIFI_ACT_FRAME - case WLC_E_ACTION_FRAME: - DHD_TRACE(("MACEVENT: %s Bssid %s\n", event_name, eabuf)); - break; -#endif /* WIFI_ACT_FRAME */ - - case WLC_E_TRACE: { - static uint32 seqnum_prev = 0; - msgtrace_hdr_t hdr; - uint32 nblost; - char *s, *p; - - buf = (uchar *) event_data; - memcpy(&hdr, buf, MSGTRACE_HDRLEN); - - if (hdr.version != MSGTRACE_VERSION) { - printf("\nMACEVENT: %s [unsupported version --> " - "dhd version:%d dongle version:%d]\n", - event_name, MSGTRACE_VERSION, hdr.version); - /* Reset datalen to avoid display below */ - datalen = 0; - break; - } - - /* There are 2 bytes available at the end of data */ - buf[MSGTRACE_HDRLEN + ntoh16(hdr.len)] = '\0'; - - if (ntoh32(hdr.discarded_bytes) || ntoh32(hdr.discarded_printf)) { - printf("\nWLC_E_TRACE: [Discarded traces in dongle -->" - "discarded_bytes %d discarded_printf %d]\n", - ntoh32(hdr.discarded_bytes), ntoh32(hdr.discarded_printf)); - } - - nblost = ntoh32(hdr.seqnum) - seqnum_prev - 1; - if (nblost > 0) { - printf("\nWLC_E_TRACE: [Event lost --> seqnum %d nblost %d\n", - ntoh32(hdr.seqnum), nblost); - } - seqnum_prev = ntoh32(hdr.seqnum); - - /* Display the trace buffer. Advance from \n to \n to avoid display big - * printf (issue with Linux printk ) - */ - p = (char *)&buf[MSGTRACE_HDRLEN]; - while ((s = strstr(p, "\n")) != NULL) { - *s = '\0'; - printf("FW: %s\n", p); - p = s+1; - } - printf("%s\n", p); - - /* Reset datalen to avoid display below */ - datalen = 0; - break; - } - - - case WLC_E_RSSI: - DHD_EVENT(("MACEVENT: %s %d\n", event_name, ntoh32(*((int *)event_data)))); - break; - - default: - DHD_EVENT(("MACEVENT: %s %d, MAC %s, status %d, reason %d, auth %d\n", - event_name, event_type, eabuf, (int)status, (int)reason, - (int)auth_type)); - break; - } - - /* show any appended data */ - if (datalen) { - buf = (uchar *) event_data; - DHD_EVENT((" data (%d) : ", datalen)); - for (i = 0; i < datalen; i++) - DHD_EVENT((" 0x%02x ", *buf++)); - DHD_EVENT(("\n")); - } -} -#endif /* SHOW_EVENTS */ - -int -wl_host_event(dhd_pub_t *dhd_pub, int *ifidx, void *pktdata, - wl_event_msg_t *event, void **data_ptr) -{ - /* check whether packet is a BRCM event pkt */ - bcm_event_t *pvt_data = (bcm_event_t *)pktdata; - uint8 *event_data; - uint32 type, status, datalen; - uint16 flags; - int evlen; - - if (bcmp(BRCM_OUI, &pvt_data->bcm_hdr.oui[0], DOT11_OUI_LEN)) { - DHD_ERROR(("%s: mismatched OUI, bailing\n", __FUNCTION__)); - return (BCME_ERROR); - } - - /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */ - if (ntoh16_ua((void *)&pvt_data->bcm_hdr.usr_subtype) != BCMILCP_BCM_SUBTYPE_EVENT) { - DHD_ERROR(("%s: mismatched subtype, bailing\n", __FUNCTION__)); - return (BCME_ERROR); - } - - *data_ptr = &pvt_data[1]; - event_data = *data_ptr; - - /* memcpy since BRCM event pkt may be unaligned. */ - memcpy(event, &pvt_data->event, sizeof(wl_event_msg_t)); - - type = ntoh32_ua((void *)&event->event_type); - flags = ntoh16_ua((void *)&event->flags); - status = ntoh32_ua((void *)&event->status); - datalen = ntoh32_ua((void *)&event->datalen); - evlen = datalen + sizeof(bcm_event_t); - - switch (type) { -#ifdef PROP_TXSTATUS - case WLC_E_FIFO_CREDIT_MAP: - dhd_wlfc_event(dhd_pub->info); - dhd_wlfc_FIFOcreditmap_event(dhd_pub->info, event_data); - WLFC_DBGMESG(("WLC_E_FIFO_CREDIT_MAP:(AC0,AC1,AC2,AC3),(BC_MC),(OTHER): " - "(%d,%d,%d,%d),(%d),(%d)\n", event_data[0], event_data[1], - event_data[2], - event_data[3], event_data[4], event_data[5])); - break; -#endif - - case WLC_E_IF: - { - dhd_if_event_t *ifevent = (dhd_if_event_t *)event_data; -#ifdef PROP_TXSTATUS - { - uint8* ea = pvt_data->eth.ether_dhost; - WLFC_DBGMESG(("WLC_E_IF: idx:%d, action:%s, iftype:%s, " - "[%02x:%02x:%02x:%02x:%02x:%02x]\n", - ifevent->ifidx, - ((ifevent->action == WLC_E_IF_ADD) ? "ADD":"DEL"), - ((ifevent->is_AP == 0) ? "STA":"AP "), - ea[0], ea[1], ea[2], ea[3], ea[4], ea[5])); - (void)ea; - - if (ifevent->action == WLC_E_IF_CHANGE) - dhd_wlfc_interface_event(dhd_pub->info, - eWLFC_MAC_ENTRY_ACTION_UPDATE, - ifevent->ifidx, ifevent->is_AP, ea); - else - dhd_wlfc_interface_event(dhd_pub->info, - ((ifevent->action == WLC_E_IF_ADD) ? - eWLFC_MAC_ENTRY_ACTION_ADD : eWLFC_MAC_ENTRY_ACTION_DEL), - ifevent->ifidx, ifevent->is_AP, ea); - - - /* dhd already has created an interface by default, for 0 */ - if (ifevent->ifidx == 0) - break; - } -#endif /* PROP_TXSTATUS */ - -#ifdef WL_CFG80211 - if (wl_cfg80211_is_progress_ifchange()) { - DHD_ERROR(("%s: ifidx %d for %s action %d\n", - __FUNCTION__, ifevent->ifidx, - event->ifname, ifevent->action)); - if (ifevent->action == WLC_E_IF_ADD - || ifevent->action == WLC_E_IF_CHANGE) - wl_cfg80211_notify_ifchange(); - return (BCME_OK); - } -#endif /* WL_CFG80211 */ - if (ifevent->ifidx > 0 && ifevent->ifidx < DHD_MAX_IFS) { - if (ifevent->action == WLC_E_IF_ADD) { - if (dhd_add_if(dhd_pub->info, ifevent->ifidx, - NULL, event->ifname, - event->addr.octet, - ifevent->flags, ifevent->bssidx)) { - DHD_ERROR(("%s: dhd_add_if failed!!" - " ifidx: %d for %s\n", - __FUNCTION__, - ifevent->ifidx, - event->ifname)); - return (BCME_ERROR); - } - } - else if (ifevent->action == WLC_E_IF_DEL) - dhd_del_if(dhd_pub->info, ifevent->ifidx); - } else { -#ifndef PROP_TXSTATUS - DHD_ERROR(("%s: Invalid ifidx %d for %s\n", - __FUNCTION__, ifevent->ifidx, event->ifname)); -#endif /* !PROP_TXSTATUS */ - } - } - /* send up the if event: btamp user needs it */ - *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); - /* push up to external supp/auth */ - dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); - break; - - -#ifdef WLMEDIA_HTSF - case WLC_E_HTSFSYNC: - htsf_update(dhd_pub->info, event_data); - break; -#endif /* WLMEDIA_HTSF */ -#if defined(NDIS630) - case WLC_E_NDIS_LINK: - break; -#else /* defined(NDIS630) && defined(BCMDONGLEHOST) */ - case WLC_E_NDIS_LINK: { - uint32 temp = hton32(WLC_E_LINK); - - memcpy((void *)(&pvt_data->event.event_type), &temp, - sizeof(pvt_data->event.event_type)); - } -#endif - /* These are what external supplicant/authenticator wants */ - /* fall through */ - case WLC_E_LINK: - case WLC_E_DEAUTH: - case WLC_E_DEAUTH_IND: - case WLC_E_DISASSOC: - case WLC_E_DISASSOC_IND: - DHD_EVENT(("%s: Link event %d, flags %x, status %x\n", - __FUNCTION__, type, flags, status)); - /* fall through */ - default: - *ifidx = dhd_ifname2idx(dhd_pub->info, event->ifname); - /* push up to external supp/auth */ - dhd_event(dhd_pub->info, (char *)pvt_data, evlen, *ifidx); - DHD_TRACE(("%s: MAC event %d, flags %x, status %x\n", - __FUNCTION__, type, flags, status)); - - /* put it back to WLC_E_NDIS_LINK */ - if (type == WLC_E_NDIS_LINK) { - uint32 temp; - - temp = ntoh32_ua((void *)&event->event_type); - DHD_TRACE(("Converted to WLC_E_LINK type %d\n", temp)); - - temp = ntoh32(WLC_E_NDIS_LINK); - memcpy((void *)(&pvt_data->event.event_type), &temp, - sizeof(pvt_data->event.event_type)); - } - break; - } - -#ifdef SHOW_EVENTS - wl_show_host_event(event, (void *)event_data); -#endif /* SHOW_EVENTS */ - - return (BCME_OK); -} - -void -wl_event_to_host_order(wl_event_msg_t * evt) -{ - /* Event struct members passed from dongle to host are stored in network - * byte order. Convert all members to host-order. - */ - evt->event_type = ntoh32(evt->event_type); - evt->flags = ntoh16(evt->flags); - evt->status = ntoh32(evt->status); - evt->reason = ntoh32(evt->reason); - evt->auth_type = ntoh32(evt->auth_type); - evt->datalen = ntoh32(evt->datalen); - evt->version = ntoh16(evt->version); -} - -void -dhd_print_buf(void *pbuf, int len, int bytes_per_line) -{ -#ifdef DHD_DEBUG - int i, j = 0; - unsigned char *buf = pbuf; - - if (bytes_per_line == 0) { - bytes_per_line = len; - } - - for (i = 0; i < len; i++) { - printf("%2.2x", *buf++); - j++; - if (j == bytes_per_line) { - printf("\n"); - j = 0; - } else { - printf(":"); - } - } - printf("\n"); -#endif /* DHD_DEBUG */ -} - -#define strtoul(nptr, endptr, base) bcm_strtoul((nptr), (endptr), (base)) - -/* Convert user's input in hex pattern to byte-size mask */ -static int -wl_pattern_atoh(char *src, char *dst) -{ - int i; - if (strncmp(src, "0x", 2) != 0 && - strncmp(src, "0X", 2) != 0) { - DHD_ERROR(("Mask invalid format. Needs to start with 0x\n")); - return -1; - } - src = src + 2; /* Skip past 0x */ - if (strlen(src) % 2 != 0) { - DHD_ERROR(("Mask invalid format. Needs to be of even length\n")); - return -1; - } - for (i = 0; *src != '\0'; i++) { - char num[3]; - bcm_strncpy_s(num, sizeof(num), src, 2); - num[2] = '\0'; - dst[i] = (uint8)strtoul(num, NULL, 16); - src += 2; - } - return i; -} - -void -dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode) -{ - char *argv[8]; - int i = 0; - const char *str; - int buf_len; - int str_len; - char *arg_save = 0, *arg_org = 0; - int rc; - char buf[128]; - wl_pkt_filter_enable_t enable_parm; - wl_pkt_filter_enable_t * pkt_filterp; - - if (!arg) - return; - - if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - goto fail; - } - arg_org = arg_save; - memcpy(arg_save, arg, strlen(arg) + 1); - - argv[i] = bcmstrtok(&arg_save, " ", 0); - - i = 0; - if (argv[i] == NULL) { - DHD_ERROR(("No args provided\n")); - goto fail; - } - - str = "pkt_filter_enable"; - str_len = strlen(str); - bcm_strncpy_s(buf, sizeof(buf), str, str_len); - buf[str_len] = '\0'; - buf_len = str_len + 1; - - pkt_filterp = (wl_pkt_filter_enable_t *)(buf + str_len + 1); - - /* Parse packet filter id. */ - enable_parm.id = htod32(strtoul(argv[i], NULL, 0)); - - /* Parse enable/disable value. */ - enable_parm.enable = htod32(enable); - - buf_len += sizeof(enable_parm); - memcpy((char *)pkt_filterp, - &enable_parm, - sizeof(enable_parm)); - - /* Enable/disable the specified filter. */ - rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); - rc = rc >= 0 ? 0 : rc; - if (rc) - DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", - __FUNCTION__, arg, rc)); - else - DHD_TRACE(("%s: successfully added pktfilter %s\n", - __FUNCTION__, arg)); - - /* Contorl the master mode */ - bcm_mkiovar("pkt_filter_mode", (char *)&master_mode, 4, buf, sizeof(buf)); - rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); - rc = rc >= 0 ? 0 : rc; - if (rc) - DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", - __FUNCTION__, arg, rc)); - -fail: - if (arg_org) - MFREE(dhd->osh, arg_org, strlen(arg) + 1); -} - -void -dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg) -{ - const char *str; - wl_pkt_filter_t pkt_filter; - wl_pkt_filter_t *pkt_filterp; - int buf_len; - int str_len; - int rc; - uint32 mask_size; - uint32 pattern_size; - char *argv[8], * buf = 0; - int i = 0; - char *arg_save = 0, *arg_org = 0; -#define BUF_SIZE 2048 - - if (!arg) - return; - - if (!(arg_save = MALLOC(dhd->osh, strlen(arg) + 1))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - goto fail; - } - - arg_org = arg_save; - - if (!(buf = MALLOC(dhd->osh, BUF_SIZE))) { - DHD_ERROR(("%s: kmalloc failed\n", __FUNCTION__)); - goto fail; - } - - memcpy(arg_save, arg, strlen(arg) + 1); - - if (strlen(arg) > BUF_SIZE) { - DHD_ERROR(("Not enough buffer %d < %d\n", (int)strlen(arg), (int)sizeof(buf))); - goto fail; - } - - argv[i] = bcmstrtok(&arg_save, " ", 0); - while (argv[i++]) - argv[i] = bcmstrtok(&arg_save, " ", 0); - - i = 0; - if (argv[i] == NULL) { - DHD_ERROR(("No args provided\n")); - goto fail; - } - - str = "pkt_filter_add"; - str_len = strlen(str); - bcm_strncpy_s(buf, BUF_SIZE, str, str_len); - buf[ str_len ] = '\0'; - buf_len = str_len + 1; - - pkt_filterp = (wl_pkt_filter_t *) (buf + str_len + 1); - - /* Parse packet filter id. */ - pkt_filter.id = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Polarity not provided\n")); - goto fail; - } - - /* Parse filter polarity. */ - pkt_filter.negate_match = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Filter type not provided\n")); - goto fail; - } - - /* Parse filter type. */ - pkt_filter.type = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Offset not provided\n")); - goto fail; - } - - /* Parse pattern filter offset. */ - pkt_filter.u.pattern.offset = htod32(strtoul(argv[i], NULL, 0)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Bitmask not provided\n")); - goto fail; - } - - /* Parse pattern filter mask. */ - mask_size = - htod32(wl_pattern_atoh(argv[i], (char *) pkt_filterp->u.pattern.mask_and_pattern)); - - if (argv[++i] == NULL) { - DHD_ERROR(("Pattern not provided\n")); - goto fail; - } - - /* Parse pattern filter pattern. */ - pattern_size = - htod32(wl_pattern_atoh(argv[i], - (char *) &pkt_filterp->u.pattern.mask_and_pattern[mask_size])); - - if (mask_size != pattern_size) { - DHD_ERROR(("Mask and pattern not the same size\n")); - goto fail; - } - - pkt_filter.u.pattern.size_bytes = mask_size; - buf_len += WL_PKT_FILTER_FIXED_LEN; - buf_len += (WL_PKT_FILTER_PATTERN_FIXED_LEN + 2 * mask_size); - - /* Keep-alive attributes are set in local variable (keep_alive_pkt), and - ** then memcpy'ed into buffer (keep_alive_pktp) since there is no - ** guarantee that the buffer is properly aligned. - */ - memcpy((char *)pkt_filterp, - &pkt_filter, - WL_PKT_FILTER_FIXED_LEN + WL_PKT_FILTER_PATTERN_FIXED_LEN); - - rc = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); - rc = rc >= 0 ? 0 : rc; - - if (rc) - DHD_TRACE(("%s: failed to add pktfilter %s, retcode = %d\n", - __FUNCTION__, arg, rc)); - else - DHD_TRACE(("%s: successfully added pktfilter %s\n", - __FUNCTION__, arg)); - -fail: - if (arg_org) - MFREE(dhd->osh, arg_org, strlen(arg) + 1); - - if (buf) - MFREE(dhd->osh, buf, BUF_SIZE); -} - -/* ========================== */ -/* ==== ARP OFFLOAD SUPPORT = */ -/* ========================== */ -#ifdef ARP_OFFLOAD_SUPPORT -void -dhd_arp_offload_set(dhd_pub_t * dhd, int arp_mode) -{ - char iovbuf[32]; - int retcode; - - bcm_mkiovar("arp_ol", (char *)&arp_mode, 4, iovbuf, sizeof(iovbuf)); - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - retcode = retcode >= 0 ? 0 : retcode; - if (retcode) - DHD_TRACE(("%s: failed to set ARP offload mode to 0x%x, retcode = %d\n", - __FUNCTION__, arp_mode, retcode)); - else - DHD_TRACE(("%s: successfully set ARP offload mode to 0x%x\n", - __FUNCTION__, arp_mode)); -} - -void -dhd_arp_offload_enable(dhd_pub_t * dhd, int arp_enable) -{ - char iovbuf[32]; - int retcode; - - bcm_mkiovar("arpoe", (char *)&arp_enable, 4, iovbuf, sizeof(iovbuf)); - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - retcode = retcode >= 0 ? 0 : retcode; - if (retcode) - DHD_TRACE(("%s: failed to enabe ARP offload to %d, retcode = %d\n", - __FUNCTION__, arp_enable, retcode)); - else - DHD_TRACE(("%s: successfully enabed ARP offload to %d\n", - __FUNCTION__, arp_enable)); -} - -void -dhd_aoe_arp_clr(dhd_pub_t *dhd) -{ - int ret = 0; - int iov_len = 0; - char iovbuf[128]; - - if (dhd == NULL) return; - - iov_len = bcm_mkiovar("arp_table_clear", 0, 0, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0) < 0)) - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); -} - -void -dhd_aoe_hostip_clr(dhd_pub_t *dhd) -{ - int ret = 0; - int iov_len = 0; - char iovbuf[128]; - - if (dhd == NULL) return; - - iov_len = bcm_mkiovar("arp_hostip_clear", 0, 0, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0)) < 0) - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); -} - -void -dhd_arp_offload_add_ip(dhd_pub_t *dhd, uint32 ipaddr) -{ - int iov_len = 0; - char iovbuf[32]; - int retcode; - - iov_len = bcm_mkiovar("arp_hostip", (char *)&ipaddr, 4, iovbuf, sizeof(iovbuf)); - retcode = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, iov_len, TRUE, 0); - - if (retcode) - DHD_TRACE(("%s: ARP ip addr add failed, retcode = %d\n", - __FUNCTION__, retcode)); - else - DHD_TRACE(("%s: sARP H ipaddr entry added \n", - __FUNCTION__)); -} - -int -dhd_arp_get_arp_hostip_table(dhd_pub_t *dhd, void *buf, int buflen) -{ - int retcode, i; - int iov_len = 0; - uint32 *ptr32 = buf; - bool clr_bottom = FALSE; - - if (!buf) - return -1; - - iov_len = bcm_mkiovar("arp_hostip", 0, 0, buf, buflen); - retcode = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, buflen, FALSE, 0); - - if (retcode) { - DHD_TRACE(("%s: ioctl WLC_GET_VAR error %d\n", - __FUNCTION__, retcode)); - - return -1; - } - - /* clean up the buf, ascii reminder */ - for (i = 0; i < MAX_IPV4_ENTRIES; i++) { - if (!clr_bottom) { - if (*ptr32 == 0) - clr_bottom = TRUE; - } else { - *ptr32 = 0; - } - ptr32++; - } - - return 0; -} -#endif /* ARP_OFFLOAD_SUPPORT */ - -/* send up locally generated event */ -void -dhd_sendup_event_common(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) -{ - switch (ntoh32(event->event_type)) { -#ifdef WLBTAMP - case WLC_E_BTA_HCI_EVENT: - break; -#endif /* WLBTAMP */ - default: - break; - } - - /* Call per-port handler. */ - dhd_sendup_event(dhdp, event, data); -} - -#ifdef SIMPLE_ISCAN - -uint iscan_thread_id = 0; -iscan_buf_t * iscan_chain = 0; - -iscan_buf_t * -dhd_iscan_allocate_buf(dhd_pub_t *dhd, iscan_buf_t **iscanbuf) -{ - iscan_buf_t *iscanbuf_alloc = 0; - iscan_buf_t *iscanbuf_head; - - DHD_ISCAN(("%s: Entered\n", __FUNCTION__)); - dhd_iscan_lock(); - - iscanbuf_alloc = (iscan_buf_t*)MALLOC(dhd->osh, sizeof(iscan_buf_t)); - if (iscanbuf_alloc == NULL) - goto fail; - - iscanbuf_alloc->next = NULL; - iscanbuf_head = *iscanbuf; - - DHD_ISCAN(("%s: addr of allocated node = 0x%X" - "addr of iscanbuf_head = 0x%X dhd = 0x%X\n", - __FUNCTION__, iscanbuf_alloc, iscanbuf_head, dhd)); - - if (iscanbuf_head == NULL) { - *iscanbuf = iscanbuf_alloc; - DHD_ISCAN(("%s: Head is allocated\n", __FUNCTION__)); - goto fail; - } - - while (iscanbuf_head->next) - iscanbuf_head = iscanbuf_head->next; - - iscanbuf_head->next = iscanbuf_alloc; - -fail: - dhd_iscan_unlock(); - return iscanbuf_alloc; -} - -void -dhd_iscan_free_buf(void *dhdp, iscan_buf_t *iscan_delete) -{ - iscan_buf_t *iscanbuf_free = 0; - iscan_buf_t *iscanbuf_prv = 0; - iscan_buf_t *iscanbuf_cur; - dhd_pub_t *dhd = dhd_bus_pub(dhdp); - DHD_ISCAN(("%s: Entered\n", __FUNCTION__)); - - dhd_iscan_lock(); - - iscanbuf_cur = iscan_chain; - - /* If iscan_delete is null then delete the entire - * chain or else delete specific one provided - */ - if (!iscan_delete) { - while (iscanbuf_cur) { - iscanbuf_free = iscanbuf_cur; - iscanbuf_cur = iscanbuf_cur->next; - iscanbuf_free->next = 0; - MFREE(dhd->osh, iscanbuf_free, sizeof(iscan_buf_t)); - } - iscan_chain = 0; - } else { - while (iscanbuf_cur) { - if (iscanbuf_cur == iscan_delete) - break; - iscanbuf_prv = iscanbuf_cur; - iscanbuf_cur = iscanbuf_cur->next; - } - if (iscanbuf_prv) - iscanbuf_prv->next = iscan_delete->next; - - iscan_delete->next = 0; - MFREE(dhd->osh, iscan_delete, sizeof(iscan_buf_t)); - - if (!iscanbuf_prv) - iscan_chain = 0; - } - dhd_iscan_unlock(); -} - -iscan_buf_t * -dhd_iscan_result_buf(void) -{ - return iscan_chain; -} - -int -dhd_iscan_issue_request(void * dhdp, wl_iscan_params_t *pParams, uint32 size) -{ - int rc = -1; - dhd_pub_t *dhd = dhd_bus_pub(dhdp); - char *buf; - char iovar[] = "iscan"; - uint32 allocSize = 0; - wl_ioctl_t ioctl; - - if (pParams) { - allocSize = (size + strlen(iovar) + 1); - if ((allocSize < size) || (allocSize < strlen(iovar))) - { - DHD_ERROR(("%s: overflow - allocation size too large %d < %d + %d!\n", - __FUNCTION__, allocSize, size, strlen(iovar))); - goto cleanUp; - } - buf = MALLOC(dhd->osh, allocSize); - - if (buf == NULL) - { - DHD_ERROR(("%s: malloc of size %d failed!\n", __FUNCTION__, allocSize)); - goto cleanUp; - } - ioctl.cmd = WLC_SET_VAR; - bcm_mkiovar(iovar, (char *)pParams, size, buf, allocSize); - rc = dhd_wl_ioctl(dhd, 0, &ioctl, buf, allocSize); - } - -cleanUp: - if (buf) { - MFREE(dhd->osh, buf, allocSize); - } - - return rc; -} - -static int -dhd_iscan_get_partial_result(void *dhdp, uint *scan_count) -{ - wl_iscan_results_t *list_buf; - wl_iscan_results_t list; - wl_scan_results_t *results; - iscan_buf_t *iscan_cur; - int status = -1; - dhd_pub_t *dhd = dhd_bus_pub(dhdp); - int rc; - wl_ioctl_t ioctl; - - DHD_ISCAN(("%s: Enter\n", __FUNCTION__)); - - iscan_cur = dhd_iscan_allocate_buf(dhd, &iscan_chain); - if (!iscan_cur) { - DHD_ERROR(("%s: Failed to allocate node\n", __FUNCTION__)); - dhd_iscan_free_buf(dhdp, 0); - dhd_iscan_request(dhdp, WL_SCAN_ACTION_ABORT); - dhd_ind_scan_confirm(dhdp, FALSE); - goto fail; - } - - dhd_iscan_lock(); - - memset(iscan_cur->iscan_buf, 0, WLC_IW_ISCAN_MAXLEN); - list_buf = (wl_iscan_results_t*)iscan_cur->iscan_buf; - results = &list_buf->results; - results->buflen = WL_ISCAN_RESULTS_FIXED_SIZE; - results->version = 0; - results->count = 0; - - memset(&list, 0, sizeof(list)); - list.results.buflen = htod32(WLC_IW_ISCAN_MAXLEN); - bcm_mkiovar("iscanresults", (char *)&list, WL_ISCAN_RESULTS_FIXED_SIZE, - iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN); - ioctl.cmd = WLC_GET_VAR; - ioctl.set = FALSE; - rc = dhd_wl_ioctl(dhd, 0, &ioctl, iscan_cur->iscan_buf, WLC_IW_ISCAN_MAXLEN); - - results->buflen = dtoh32(results->buflen); - results->version = dtoh32(results->version); - *scan_count = results->count = dtoh32(results->count); - status = dtoh32(list_buf->status); - DHD_ISCAN(("%s: Got %d resuls status = (%x)\n", __FUNCTION__, results->count, status)); - - dhd_iscan_unlock(); - - if (!(*scan_count)) { - /* TODO: race condition when FLUSH already called */ - dhd_iscan_free_buf(dhdp, 0); - } -fail: - return status; -} - -#endif /* SIMPLE_ISCAN */ - -/* - * returns = TRUE if associated, FALSE if not associated - */ -bool dhd_is_associated(dhd_pub_t *dhd, void *bss_buf, int *retval) -{ - char bssid[6], zbuf[6]; - int ret = -1; - - bzero(bssid, 6); - bzero(zbuf, 6); - - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_BSSID, (char *)&bssid, ETHER_ADDR_LEN, FALSE, 0); - DHD_TRACE((" %s WLC_GET_BSSID ioctl res = %d\n", __FUNCTION__, ret)); - - if (ret == BCME_NOTASSOCIATED) { - DHD_TRACE(("%s: not associated! res:%d\n", __FUNCTION__, ret)); - } - if (retval) - *retval = ret; - - if (ret < 0) - return FALSE; - - if ((memcmp(bssid, zbuf, ETHER_ADDR_LEN) != 0)) { - /* STA is assocoated BSSID is non zero */ - - if (bss_buf) { - /* return bss if caller provided buf */ - memcpy(bss_buf, bssid, ETHER_ADDR_LEN); - } - return TRUE; - } else { - DHD_TRACE(("%s: WLC_GET_BSSID ioctl returned zero bssid\n", __FUNCTION__)); - return FALSE; - } -} - - -/* Function to estimate possible DTIM_SKIP value */ -int -dhd_get_dtim_skip(dhd_pub_t *dhd) -{ - int bcn_li_dtim; - int ret = -1; - int dtim_assoc = 0; - - if ((dhd->dtim_skip == 0) || (dhd->dtim_skip == 1)) - bcn_li_dtim = 3; - else - bcn_li_dtim = dhd->dtim_skip; - - /* Check if associated */ - if (dhd_is_associated(dhd, NULL, NULL) == FALSE) { - DHD_TRACE(("%s NOT assoc ret %d\n", __FUNCTION__, ret)); - goto exit; - } - - /* if assoc grab ap's dtim value */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_DTIMPRD, - &dtim_assoc, sizeof(dtim_assoc), FALSE, 0)) < 0) { - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); - goto exit; - } - - DHD_ERROR(("%s bcn_li_dtim=%d DTIM=%d Listen=%d\n", - __FUNCTION__, bcn_li_dtim, dtim_assoc, LISTEN_INTERVAL)); - - /* if not assocated just eixt */ - if (dtim_assoc == 0) { - goto exit; - } - - /* check if sta listen interval fits into AP dtim */ - if (dtim_assoc > LISTEN_INTERVAL) { - /* AP DTIM to big for our Listen Interval : no dtim skiping */ - bcn_li_dtim = 1; - DHD_ERROR(("%s DTIM=%d > Listen=%d : too big ...\n", - __FUNCTION__, dtim_assoc, LISTEN_INTERVAL)); - goto exit; - } - - if ((bcn_li_dtim * dtim_assoc) > LISTEN_INTERVAL) { - /* Round up dtim_skip to fit into STAs Listen Interval */ - bcn_li_dtim = (int)(LISTEN_INTERVAL / dtim_assoc); - DHD_TRACE(("%s agjust dtim_skip as %d\n", __FUNCTION__, bcn_li_dtim)); - } - -exit: - return bcn_li_dtim; -} - -/* Check if HostAPD or WFD mode setup */ -bool dhd_check_ap_wfd_mode_set(dhd_pub_t *dhd) -{ -#ifdef WL_CFG80211 - if ((dhd->op_mode & CONCURRENT_MASK) == CONCURRENT_MASK) - return FALSE; - if (((dhd->op_mode & HOSTAPD_MASK) == HOSTAPD_MASK) || - ((dhd->op_mode & WFD_MASK) == WFD_MASK)) - return TRUE; - else -#endif /* WL_CFG80211 */ - return FALSE; -} - -#if defined(PNO_SUPPORT) -int -dhd_pno_clean(dhd_pub_t *dhd) -{ - char iovbuf[128]; - int pfn_enabled = 0; - int iov_len = 0; - int ret; - - /* Disable pfn */ - iov_len = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) >= 0) { - /* clear pfn */ - iov_len = bcm_mkiovar("pfnclear", 0, 0, iovbuf, sizeof(iovbuf)); - if (iov_len) { - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - iov_len, TRUE, 0)) < 0) { - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); - } - } - else { - ret = -1; - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, iov_len)); - } - } - else - DHD_ERROR(("%s failed code %d\n", __FUNCTION__, ret)); - - return ret; -} - -int -dhd_pno_enable(dhd_pub_t *dhd, int pfn_enabled) -{ - char iovbuf[128]; - int ret = -1; - - if ((!dhd) && ((pfn_enabled != 0) || (pfn_enabled != 1))) { - DHD_ERROR(("%s error exit\n", __FUNCTION__)); - return ret; - } - - if (dhd_check_ap_wfd_mode_set(dhd) == TRUE) - return (ret); - - memset(iovbuf, 0, sizeof(iovbuf)); - - if ((pfn_enabled) && (dhd_is_associated(dhd, NULL, NULL) == TRUE)) { - DHD_ERROR(("%s pno is NOT enable : called in assoc mode , ignore\n", __FUNCTION__)); - return ret; - } - - /* Enable/disable PNO */ - if ((ret = bcm_mkiovar("pfn", (char *)&pfn_enabled, 4, iovbuf, sizeof(iovbuf))) > 0) { - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, - iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s failed for error=%d\n", __FUNCTION__, ret)); - return ret; - } - else { - dhd->pno_enable = pfn_enabled; - DHD_TRACE(("%s set pno as %s\n", - __FUNCTION__, dhd->pno_enable ? "Enable" : "Disable")); - } - } - else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, ret)); - - return ret; -} - -/* Function to execute combined scan */ -int -dhd_pno_set(dhd_pub_t *dhd, wlc_ssid_t* ssids_local, int nssid, ushort scan_fr, - int pno_repeat, int pno_freq_expo_max) -{ - int err = -1; - char iovbuf[128]; - int k, i; - wl_pfn_param_t pfn_param; - wl_pfn_t pfn_element; - uint len = 0; - - DHD_TRACE(("%s nssid=%d nchan=%d\n", __FUNCTION__, nssid, scan_fr)); - - if ((!dhd) || (!ssids_local)) { - DHD_ERROR(("%s error exit(%s %s)\n", __FUNCTION__, (!dhd)?"dhd is null":"", (!ssids_local)?"ssids is null":"")); - err = -1; - return err; - } - - if (dhd_check_ap_wfd_mode_set(dhd) == TRUE) - return (err); - - /* Check for broadcast ssid */ - for (k = 0; k < nssid; k++) { - if (!ssids_local[k].SSID_len) { - DHD_ERROR(("%d: Broadcast SSID is ilegal for PNO setting\n", k)); - return err; - } - } -/* #define PNO_DUMP 1 */ -#ifdef PNO_DUMP - { - int j; - for (j = 0; j < nssid; j++) { - DHD_ERROR(("%d: scan for %s size =%d\n", j, - ssids_local[j].SSID, ssids_local[j].SSID_len)); - } - } -#endif /* PNO_DUMP */ - - /* clean up everything */ - if ((err = dhd_pno_clean(dhd)) < 0) { - DHD_ERROR(("%s failed error=%d\n", __FUNCTION__, err)); - return err; - } - memset(iovbuf, 0, sizeof(iovbuf)); - memset(&pfn_param, 0, sizeof(pfn_param)); - memset(&pfn_element, 0, sizeof(pfn_element)); - - /* set pfn parameters */ - pfn_param.version = htod32(PFN_VERSION); - pfn_param.flags = htod16((PFN_LIST_ORDER << SORT_CRITERIA_BIT)); - - /* check and set extra pno params */ - if ((pno_repeat != 0) || (pno_freq_expo_max != 0)) { - pfn_param.flags |= htod16(ENABLE << ENABLE_ADAPTSCAN_BIT); - pfn_param.repeat = (uchar) (pno_repeat); - pfn_param.exp = (uchar) (pno_freq_expo_max); - } - /* set up pno scan fr */ - if (scan_fr != 0) - pfn_param.scan_freq = htod32(scan_fr); - - if (pfn_param.scan_freq > PNO_SCAN_MAX_FW_SEC) { - DHD_ERROR(("%s pno freq above %d sec\n", __FUNCTION__, PNO_SCAN_MAX_FW_SEC)); - return err; - } - if (pfn_param.scan_freq < PNO_SCAN_MIN_FW_SEC) { - DHD_ERROR(("%s pno freq less %d sec\n", __FUNCTION__, PNO_SCAN_MIN_FW_SEC)); - return err; - } - - len = bcm_mkiovar("pfn_set", (char *)&pfn_param, sizeof(pfn_param), iovbuf, sizeof(iovbuf)); - if ((err = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) { - DHD_ERROR(("%s pfn_set failed for error=%d\n", - __FUNCTION__, err)); - return err; - } - - /* set all pfn ssid */ - for (i = 0; i < nssid; i++) { - - pfn_element.infra = htod32(DOT11_BSSTYPE_INFRASTRUCTURE); - pfn_element.auth = (DOT11_OPEN_SYSTEM); - pfn_element.wpa_auth = htod32(WPA_AUTH_PFN_ANY); - pfn_element.wsec = htod32(0); - pfn_element.infra = htod32(1); - pfn_element.bss_type = htod32(ENABLE << WL_PFN_HIDDEN_BIT); - memcpy((char *)pfn_element.ssid.SSID, ssids_local[i].SSID, ssids_local[i].SSID_len); - pfn_element.ssid.SSID_len = ssids_local[i].SSID_len; - - if ((len = - bcm_mkiovar("pfn_add", (char *)&pfn_element, - sizeof(pfn_element), iovbuf, sizeof(iovbuf))) > 0) { - if ((err = - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, len, TRUE, 0)) < 0) { - DHD_ERROR(("%s failed for i=%d error=%d\n", - __FUNCTION__, i, err)); - return err; - } - else - DHD_TRACE(("%s set OK with PNO time=%d repeat=%d max_adjust=%d\n", - __FUNCTION__, pfn_param.scan_freq, - pfn_param.repeat, pfn_param.exp)); - } - else DHD_ERROR(("%s failed err=%d\n", __FUNCTION__, err)); - } - - /* Enable PNO */ - /* dhd_pno_enable(dhd, 1); */ - return err; -} - -int -dhd_pno_get_status(dhd_pub_t *dhd) -{ - int ret = -1; - - if (!dhd) - return ret; - else - return (dhd->pno_enable); -} - -#endif /* PNO_SUPPORT */ - -#if defined(KEEP_ALIVE) -int dhd_keep_alive_onoff(dhd_pub_t *dhd) -{ - char buf[256]; - const char *str; - wl_mkeep_alive_pkt_t mkeep_alive_pkt; - wl_mkeep_alive_pkt_t *mkeep_alive_pktp; - int buf_len; - int str_len; - int res = -1; - - if (dhd_check_ap_wfd_mode_set(dhd) == TRUE) - return (res); - - DHD_TRACE(("%s execution\n", __FUNCTION__)); - - str = "mkeep_alive"; - str_len = strlen(str); - strncpy(buf, str, str_len); - buf[ str_len ] = '\0'; - mkeep_alive_pktp = (wl_mkeep_alive_pkt_t *) (buf + str_len + 1); - mkeep_alive_pkt.period_msec = KEEP_ALIVE_PERIOD; - buf_len = str_len + 1; - mkeep_alive_pkt.version = htod16(WL_MKEEP_ALIVE_VERSION); - mkeep_alive_pkt.length = htod16(WL_MKEEP_ALIVE_FIXED_LEN); - /* Setup keep alive zero for null packet generation */ - mkeep_alive_pkt.keep_alive_id = 0; - mkeep_alive_pkt.len_bytes = 0; - buf_len += WL_MKEEP_ALIVE_FIXED_LEN; - /* Keep-alive attributes are set in local variable (mkeep_alive_pkt), and - * then memcpy'ed into buffer (mkeep_alive_pktp) since there is no - * guarantee that the buffer is properly aligned. - */ - memcpy((char *)mkeep_alive_pktp, &mkeep_alive_pkt, WL_MKEEP_ALIVE_FIXED_LEN); - - res = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, buf_len, TRUE, 0); - - return res; -} -#endif /* defined(KEEP_ALIVE) */ -/* Android ComboSCAN support */ - -/* - * data parsing from ComboScan tlv list -*/ -int -wl_iw_parse_data_tlv(char** list_str, void *dst, int dst_size, const char token, - int input_size, int *bytes_left) -{ - char* str = *list_str; - uint16 short_temp; - uint32 int_temp; - - if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { - DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return -1; - } - - /* Clean all dest bytes */ - memset(dst, 0, dst_size); - while (*bytes_left > 0) { - - if (str[0] != token) { - DHD_TRACE(("%s NOT Type=%d get=%d left_parse=%d \n", - __FUNCTION__, token, str[0], *bytes_left)); - return -1; - } - - *bytes_left -= 1; - str += 1; - - if (input_size == 1) { - memcpy(dst, str, input_size); - } - else if (input_size == 2) { - memcpy(dst, (char *)htod16(memcpy(&short_temp, str, input_size)), - input_size); - } - else if (input_size == 4) { - memcpy(dst, (char *)htod32(memcpy(&int_temp, str, input_size)), - input_size); - } - - *bytes_left -= input_size; - str += input_size; - *list_str = str; - return 1; - } - return 1; -} - -/* - * channel list parsing from cscan tlv list -*/ -int -wl_iw_parse_channel_list_tlv(char** list_str, uint16* channel_list, - int channel_num, int *bytes_left) -{ - char* str = *list_str; - int idx = 0; - - if ((list_str == NULL) || (*list_str == NULL) ||(bytes_left == NULL) || (*bytes_left < 0)) { - DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return -1; - } - - while (*bytes_left > 0) { - - if (str[0] != CSCAN_TLV_TYPE_CHANNEL_IE) { - *list_str = str; - DHD_TRACE(("End channel=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); - return idx; - } - /* Get proper CSCAN_TLV_TYPE_CHANNEL_IE */ - *bytes_left -= 1; - str += 1; - - if (str[0] == 0) { - /* All channels */ - channel_list[idx] = 0x0; - } - else { - channel_list[idx] = (uint16)str[0]; - DHD_TRACE(("%s channel=%d \n", __FUNCTION__, channel_list[idx])); - } - *bytes_left -= 1; - str += 1; - - if (idx++ > 255) { - DHD_ERROR(("%s Too many channels \n", __FUNCTION__)); - return -1; - } - } - - *list_str = str; - return idx; -} - -/* - * SSIDs list parsing from cscan tlv list - */ -int -wl_iw_parse_ssid_list_tlv(char** list_str, wlc_ssid_t* ssid, int max, int *bytes_left) -{ - char* str; - int idx = 0; - - if ((list_str == NULL) || (*list_str == NULL) || (*bytes_left < 0)) { - DHD_ERROR(("%s error paramters\n", __FUNCTION__)); - return -1; - } - str = *list_str; - while (*bytes_left > 0) { - - if (str[0] != CSCAN_TLV_TYPE_SSID_IE) { - *list_str = str; - DHD_TRACE(("nssid=%d left_parse=%d %d\n", idx, *bytes_left, str[0])); - return idx; - } - - /* Get proper CSCAN_TLV_TYPE_SSID_IE */ - *bytes_left -= 1; - str += 1; - - if (str[0] == 0) { - /* Broadcast SSID */ - ssid[idx].SSID_len = 0; - memset((char*)ssid[idx].SSID, 0x0, DOT11_MAX_SSID_LEN); - *bytes_left -= 1; - str += 1; - - DHD_TRACE(("BROADCAST SCAN left=%d\n", *bytes_left)); - } - else if (str[0] <= DOT11_MAX_SSID_LEN) { - /* Get proper SSID size */ - ssid[idx].SSID_len = str[0]; - *bytes_left -= 1; - str += 1; - - /* Get SSID */ - if (ssid[idx].SSID_len > *bytes_left) { - DHD_ERROR(("%s out of memory range len=%d but left=%d\n", - __FUNCTION__, ssid[idx].SSID_len, *bytes_left)); - return -1; - } - - memcpy((char*)ssid[idx].SSID, str, ssid[idx].SSID_len); - - *bytes_left -= ssid[idx].SSID_len; - str += ssid[idx].SSID_len; - - DHD_TRACE(("%s :size=%d left=%d\n", - (char*)ssid[idx].SSID, ssid[idx].SSID_len, *bytes_left)); - } - else { - DHD_ERROR(("### SSID size more that %d\n", str[0])); - return -1; - } - - if (idx++ > max) { - DHD_ERROR(("%s number of SSIDs more that %d\n", __FUNCTION__, idx)); - return -1; - } - } - - *list_str = str; - return idx; -} - -/* Parse a comma-separated list from list_str into ssid array, starting - * at index idx. Max specifies size of the ssid array. Parses ssids - * and returns updated idx; if idx >= max not all fit, the excess have - * not been copied. Returns -1 on empty string, or on ssid too long. - */ -int -wl_iw_parse_ssid_list(char** list_str, wlc_ssid_t* ssid, int idx, int max) -{ - char* str, *ptr; - - if ((list_str == NULL) || (*list_str == NULL)) - return -1; - - for (str = *list_str; str != NULL; str = ptr) { - - /* check for next TAG */ - if (!strncmp(str, GET_CHANNEL, strlen(GET_CHANNEL))) { - *list_str = str + strlen(GET_CHANNEL); - return idx; - } - - if ((ptr = strchr(str, ',')) != NULL) { - *ptr++ = '\0'; - } - - if (strlen(str) > DOT11_MAX_SSID_LEN) { - DHD_ERROR(("ssid <%s> exceeds %d\n", str, DOT11_MAX_SSID_LEN)); - return -1; - } - - if (strlen(str) == 0) - ssid[idx].SSID_len = 0; - - if (idx < max) { - bcm_strcpy_s((char*)ssid[idx].SSID, sizeof(ssid[idx].SSID), str); - ssid[idx].SSID_len = strlen(str); - } - idx++; - } - return idx; -} - -/* - * Parse channel list from iwpriv CSCAN - */ -int -wl_iw_parse_channel_list(char** list_str, uint16* channel_list, int channel_num) -{ - int num; - int val; - char* str; - char* endptr = NULL; - - if ((list_str == NULL)||(*list_str == NULL)) - return -1; - - str = *list_str; - num = 0; - while (strncmp(str, GET_NPROBE, strlen(GET_NPROBE))) { - val = (int)strtoul(str, &endptr, 0); - if (endptr == str) { - printf("could not parse channel number starting at" - " substring \"%s\" in list:\n%s\n", - str, *list_str); - return -1; - } - str = endptr + strspn(endptr, " ,"); - - if (num == channel_num) { - DHD_ERROR(("too many channels (more than %d) in channel list:\n%s\n", - channel_num, *list_str)); - return -1; - } - - channel_list[num++] = (uint16)val; - } - *list_str = str; - return num; -} diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_gpio.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_gpio.c deleted file mode 100644 index 433a12d..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_gpio.c +++ /dev/null @@ -1,316 +0,0 @@ -/* -* Customer code to add GPIO control during WLAN start/stop -* Copyright (C) 1999-2012, Broadcom Corporation -* -* Unless you and Broadcom execute a separate written software license -* agreement governing use of this software, this software is licensed to you -* under the terms of the GNU General Public License version 2 (the "GPL"), -* available at http://www.broadcom.com/licenses/GPLv2.php, with the -* following added to such license: -* -* As a special exception, the copyright holders of this software give you -* permission to link this software with independent modules, and to copy and -* distribute the resulting executable under terms of your choice, provided that -* you also meet, for each linked independent module, the terms and conditions of -* the license of that module. An independent module is a module which is not -* derived from this software. The special exception does not apply to any -* modifications of the software. -* -* Notwithstanding the above, under no circumstances may you combine this -* software in any way with any other Broadcom software provided under a license -* other than the GPL, without Broadcom's express prior written consent. -* -* $Id: dhd_custom_gpio.c 291086 2011-10-21 01:17:24Z $ -*/ - -#include <typedefs.h> -#include <linuxver.h> -#include <osl.h> -#include <bcmutils.h> - -#include <dngl_stats.h> -#include <dhd.h> - -#include <wlioctl.h> -#include <wl_iw.h> - -#define WL_ERROR(x) printf x -#define WL_TRACE(x) - -#ifdef CUSTOMER_HW -extern void bcm_wlan_power_off(int); -extern void bcm_wlan_power_on(int); -#endif /* CUSTOMER_HW */ -#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW_SAMSUNG) -#ifdef CONFIG_WIFI_CONTROL_FUNC -int wifi_set_power(int on, unsigned long msec); -int wifi_get_irq_number(unsigned long *irq_flags_ptr); -int wifi_get_mac_addr(unsigned char *buf); -void *wifi_get_country_code(char *ccode); -#else -int wifi_set_power(int on, unsigned long msec) { return -1; } -int wifi_get_irq_number(unsigned long *irq_flags_ptr) { return -1; } -int wifi_get_mac_addr(unsigned char *buf) { return -1; } -void *wifi_get_country_code(char *ccode) { return NULL; } -#endif /* CONFIG_WIFI_CONTROL_FUNC */ -#endif /* CUSTOMER_HW2 || CUSTOMER_HW_SAMSUNG */ - -#if defined(OOB_INTR_ONLY) - -#if defined(BCMLXSDMMC) -extern int sdioh_mmc_irq(int irq); -#endif /* (BCMLXSDMMC) */ - -#ifdef CUSTOMER_HW3 -#include <mach/gpio.h> -#endif - -/* Customer specific Host GPIO defintion */ -static int dhd_oob_gpio_num = -1; - -module_param(dhd_oob_gpio_num, int, 0644); -MODULE_PARM_DESC(dhd_oob_gpio_num, "DHD oob gpio number"); - -/* This function will return: - * 1) return : Host gpio interrupt number per customer platform - * 2) irq_flags_ptr : Type of Host interrupt as Level or Edge - * - * NOTE : - * Customer should check his platform definitions - * and his Host Interrupt spec - * to figure out the proper setting for his platform. - * Broadcom provides just reference settings as example. - * - */ -int dhd_customer_oob_irq_map(unsigned long *irq_flags_ptr) -{ - int host_oob_irq = 0; - -#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW_SAMSUNG) - host_oob_irq = wifi_get_irq_number(irq_flags_ptr); - -#else -#if defined(CUSTOM_OOB_GPIO_NUM) - if (dhd_oob_gpio_num < 0) { - dhd_oob_gpio_num = CUSTOM_OOB_GPIO_NUM; - } -#endif /* CUSTOMER_OOB_GPIO_NUM */ - - if (dhd_oob_gpio_num < 0) { - WL_ERROR(("%s: ERROR customer specific Host GPIO is NOT defined \n", - __FUNCTION__)); - return (dhd_oob_gpio_num); - } - - WL_ERROR(("%s: customer specific Host GPIO number is (%d)\n", - __FUNCTION__, dhd_oob_gpio_num)); - -#if defined CUSTOMER_HW - host_oob_irq = MSM_GPIO_TO_INT(dhd_oob_gpio_num); -#elif defined CUSTOMER_HW3 - gpio_request(dhd_oob_gpio_num, "oob irq"); - host_oob_irq = gpio_to_irq(dhd_oob_gpio_num); - gpio_direction_input(dhd_oob_gpio_num); -#endif /* CUSTOMER_HW */ -#endif /* CUSTOMER_HW2 || CUSTOMER_HW_SAMSUNG */ - - return (host_oob_irq); -} -#endif /* defined(OOB_INTR_ONLY) */ - -/* Customer function to control hw specific wlan gpios */ -void -dhd_customer_gpio_wlan_ctrl(int onoff) -{ - switch (onoff) { - case WLAN_RESET_OFF: - WL_TRACE(("%s: call customer specific GPIO to insert WLAN RESET\n", - __FUNCTION__)); -#ifdef CUSTOMER_HW - bcm_wlan_power_off(2); -#endif /* CUSTOMER_HW */ -#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW_SAMSUNG) - wifi_set_power(0, 0); -#endif - WL_ERROR(("=========== WLAN placed in RESET ========\n")); - break; - - case WLAN_RESET_ON: - WL_TRACE(("%s: callc customer specific GPIO to remove WLAN RESET\n", - __FUNCTION__)); -#ifdef CUSTOMER_HW - bcm_wlan_power_on(2); -#endif /* CUSTOMER_HW */ -#if defined(CUSTOMER_HW2) || defined(CUSTOMER_HW_SAMSUNG) - wifi_set_power(1, 0); -#endif - WL_ERROR(("=========== WLAN going back to live ========\n")); - break; - - case WLAN_POWER_OFF: - WL_TRACE(("%s: call customer specific GPIO to turn off WL_REG_ON\n", - __FUNCTION__)); -#ifdef CUSTOMER_HW - bcm_wlan_power_off(1); -#endif /* CUSTOMER_HW */ - break; - - case WLAN_POWER_ON: - WL_TRACE(("%s: call customer specific GPIO to turn on WL_REG_ON\n", - __FUNCTION__)); -#ifdef CUSTOMER_HW - bcm_wlan_power_on(1); - /* Lets customer power to get stable */ - OSL_DELAY(200); -#endif /* CUSTOMER_HW */ - break; - } -} - -#ifdef GET_CUSTOM_MAC_ENABLE -/* Function to get custom MAC address */ -int -dhd_custom_get_mac_address(unsigned char *buf) -{ - int ret = 0; - - WL_TRACE(("%s Enter\n", __FUNCTION__)); - if (!buf) - return -EINVAL; - - /* Customer access to MAC address stored outside of DHD driver */ -#if defined(CUSTOMER_HW2) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35)) - ret = wifi_get_mac_addr(buf); -#endif - -#ifdef EXAMPLE_GET_MAC - /* EXAMPLE code */ - { - struct ether_addr ea_example = {{0x00, 0x11, 0x22, 0x33, 0x44, 0xFF}}; - bcopy((char *)&ea_example, buf, sizeof(struct ether_addr)); - } -#endif /* EXAMPLE_GET_MAC */ - - return ret; -} -#endif /* GET_CUSTOM_MAC_ENABLE */ - -/* Customized Locale table : OPTIONAL feature */ -const struct cntry_locales_custom translate_custom_table[] = { -/* Table should be filled out based on custom platform regulatory requirement */ -#ifdef BCM4334_CHIP - {"", "XZ", 11}, /* Universal if Country code is unknown or empty */ -#endif - {"AE", "AE", 1}, - {"AR", "AR", 1}, - {"AT", "AT", 1}, - {"AU", "AU", 2}, - {"BE", "BE", 1}, - {"BG", "BG", 1}, - {"BN", "BN", 1}, - {"CA", "CA", 2}, - {"CH", "CH", 1}, - {"CN", "CN", 0}, - {"CY", "CY", 1}, - {"CZ", "CZ", 1}, - {"DE", "DE", 3}, - {"DK", "DK", 1}, - {"EE", "EE", 1}, - {"ES", "ES", 1}, - {"FI", "FI", 1}, - {"FR", "FR", 1}, - {"GB", "GB", 1}, - {"GR", "GR", 1}, - {"HR", "HR", 1}, - {"HU", "HU", 1}, - {"IE", "IE", 1}, - {"IS", "IS", 1}, - {"IT", "IT", 1}, - {"JP", "JP", 5}, - {"KR", "KR", 24}, - {"KW", "KW", 1}, - {"LI", "LI", 1}, - {"LT", "LT", 1}, - {"LU", "LU", 1}, - {"LV", "LV", 1}, - {"MA", "MA", 1}, - {"MT", "MT", 1}, - {"MX", "MX", 1}, - {"NL", "NL", 1}, - {"NO", "NO", 1}, - {"PL", "PL", 1}, - {"PT", "PT", 1}, - {"PY", "PY", 1}, - {"RO", "RO", 1}, - {"SE", "SE", 1}, - {"SI", "SI", 1}, - {"SK", "SK", 1}, - {"TR", "TR", 7}, - {"TW", "TW", 2}, -#ifdef CUSTOMER_HW_SAMSUNG - {"IR", "XZ", 11}, /* Universal if Country code is IRAN, (ISLAMIC REPUBLIC OF) */ - {"SD", "XZ", 11}, /* Universal if Country code is SUDAN */ - {"SY", "XZ", 11}, /* Universal if Country code is SYRIAN ARAB REPUBLIC */ - {"GL", "XZ", 11}, /* Universal if Country code is GREENLAND */ - {"PS", "XZ", 11}, /* Universal if Country code is PALESTINIAN TERRITORY, OCCUPIED */ - {"TL", "XZ", 11}, /* Universal if Country code is TIMOR-LESTE (EAST TIMOR) */ - {"MH", "XZ", 11}, /* Universal if Country code is MARSHALL ISLANDS */ - {"PK", "XZ", 11}, /* Universal if Country code is PAKISTAN*/ -#endif -#ifdef BCM4334_CHIP - {"RU", "RU", 5}, - {"SG", "SG", 4}, - {"US", "US", 46} -#endif -#ifdef BCM4330_CHIP - {"RU", "RU", 1}, - {"US", "US", 5} -#endif -}; - - -/* Customized Locale convertor -* input : ISO 3166-1 country abbreviation -* output: customized cspec -*/ -void get_customized_country_code(char *country_iso_code, wl_country_t *cspec) -{ -#ifndef CUSTOMER_HW_SAMSUNG - struct cntry_locales_custom *cloc_ptr; - - if (!cspec) - return; - - cloc_ptr = wifi_get_country_code(country_iso_code); - if (cloc_ptr) { - strlcpy(cspec->ccode, cloc_ptr->custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = cloc_ptr->custom_locale_rev; - } - return; -#else - int size, i; - - size = ARRAYSIZE(translate_custom_table); - - if (cspec == 0) - return; - - if (size == 0) - return; - - for (i = 0; i < size; i++) { - if (strcmp(country_iso_code, translate_custom_table[i].iso_abbrev) == 0) { - memcpy(cspec->ccode, - translate_custom_table[i].custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = translate_custom_table[i].custom_locale_rev; - return; - } - } -#ifdef EXAMPLE_TABLE - /* if no country code matched return first universal code from translate_custom_table */ - memcpy(cspec->ccode, translate_custom_table[0].custom_locale, WLC_CNTRY_BUF_SZ); - cspec->rev = translate_custom_table[0].custom_locale_rev; -#endif /* EXMAPLE_TABLE */ - return; -#endif /* CUSTOMER_HW_SAMSUNG) */ -} diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_sec.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_sec.c deleted file mode 100644 index 74c5da3..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_custom_sec.c +++ /dev/null @@ -1,989 +0,0 @@ -/* Function list - 1. Module Type - a. For CID - Use 'USE_CID_CHECK' Feature - dhd_write_cid_file(), dhd_dump_cis(), dhd_check_module_cid() - b. For MAC - Use 'GET_MAC_FROM_OTP' Feature - dhd_write_mac_file(), dhd_check_module_mac() - 2. COB Type - a. For MAC - Use 'READ_MACADDR' Feature - dhd_read_macaddr() - 3. Etc - a. Power Save Mode - Use 'CONFIG_CONTROL_PM' Feature - sec_control_pm() - b. U1 Module only - Use 'WRITE_MACADDR' Feature - dhd_write_macaddr -*/ - -#include <typedefs.h> -#include <linuxver.h> -#include <osl.h> - -#include <proto/ethernet.h> -#include <dngl_stats.h> -#include <bcmutils.h> -#include <dhd.h> -#include <dhd_dbg.h> - -#include <linux/fcntl.h> -#include <linux/fs.h> - -struct dhd_info; -extern int _dhd_set_mac_address(struct dhd_info *dhd, - int ifidx, struct ether_addr *addr); - -#ifdef SLP_PATH -#define CIDINFO "/opt/etc/.cid.info" -#define PSMINFO "/opt/etc/.psm.info" -#define MACINFO "/opt/etc/.mac.info" -#define MACINFO_EFS NULL -#define REVINFO "/data/.rev" -#else -#define MACINFO "/data/.mac.info" -#define MACINFO_EFS "/efs/wifi/.mac.info" -#define NVMACINFO "/data/.nvmac.info" -#define REVINFO "/data/.rev" -#define CIDINFO "/data/.cid.info" -#define PSMINFO "/data/.psm.info" -#endif /*SLP_PATH*/ - -#ifdef READ_MACADDR -int dhd_read_macaddr(struct dhd_info *dhd, struct ether_addr *mac) -{ - struct file *fp = NULL; - char macbuffer[18] = {0}; - mm_segment_t oldfs = {0}; - char randommac[3] = {0}; - char buf[18] = {0}; - char *filepath_efs = MACINFO_EFS; -#ifdef CONFIG_TARGET_LOCALE_VZW - char *nvfilepath = "/data/misc/wifi/.nvmac.info"; -#else - char *nvfilepath = NVMACINFO; -#endif - int ret = 0; - - fp = filp_open(filepath_efs, O_RDONLY, 0); - if (IS_ERR(fp)) { -start_readmac: - /* File Doesn't Exist. Create and write mac addr.*/ - fp = filp_open(filepath_efs, O_RDWR | O_CREAT, 0666); - if (IS_ERR(fp)) { - DHD_ERROR(("[WIFI] %s: File open error\n", filepath_efs)); - return -1; - } - oldfs = get_fs(); - set_fs(get_ds()); - - /* Generating the Random Bytes for 3 last octects of the MAC address */ - get_random_bytes(randommac, 3); - - sprintf(macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X\n", - 0x00, 0x12, 0x34, randommac[0], randommac[1], randommac[2]); - DHD_ERROR(("[WIFI]The Random Generated MAC ID: %s\n", macbuffer)); - - if (fp->f_mode & FMODE_WRITE) { - ret = fp->f_op->write(fp, (const char *)macbuffer, sizeof(macbuffer), &fp->f_pos); - if (ret < 0) - DHD_ERROR(("[WIFI]MAC address [%s] Failed to write into File: %s\n", macbuffer, filepath_efs)); - else - DHD_ERROR(("[WIFI]MAC address [%s] written into File: %s\n", macbuffer, filepath_efs)); - } - set_fs(oldfs); - /* Reading the MAC Address from .mac.info file( the existed file or just created file)*/ - ret = kernel_read(fp, 0, buf, 18); - } else { - /* Reading the MAC Address from .mac.info file( the existed file or just created file)*/ - ret = kernel_read(fp, 0, buf, 18); -/* to prevent abnormal string display when mac address is displayed on the screen. */ - buf[17] = '\0'; - DHD_ERROR(("Read MAC : [%s] [%d] \r\n" , buf, strncmp(buf , "00:00:00:00:00:00" , 17))); - if (strncmp(buf , "00:00:00:00:00:00" , 17) < 1) { - DHD_ERROR(("goto start_readmac \r\n")); - filp_close(fp, NULL); - goto start_readmac; - } - } - - if (ret) - sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", - (unsigned int *)&(mac->octet[0]), (unsigned int *)&(mac->octet[1]), - (unsigned int *)&(mac->octet[2]), (unsigned int *)&(mac->octet[3]), - (unsigned int *)&(mac->octet[4]), (unsigned int *)&(mac->octet[5])); - else - DHD_ERROR(("dhd_bus_start: Reading from the '%s' returns 0 bytes\n", filepath_efs)); - - if (fp) - filp_close(fp, NULL); - - /* Writing Newly generated MAC ID to the Dongle */ - if (0 == _dhd_set_mac_address(dhd, 0, mac)) - DHD_INFO(("dhd_bus_start: MACID is overwritten\n")); - else - DHD_ERROR(("dhd_bus_start: _dhd_set_mac_address() failed\n")); - - return 0; -} -#endif /* READ_MACADDR */ - -#ifdef RDWR_MACADDR -static int g_imac_flag; - -enum { - MACADDR_NONE = 0 , - MACADDR_MOD, - MACADDR_MOD_RANDOM, - MACADDR_MOD_NONE, - MACADDR_COB, - MACADDR_COB_RANDOM -}; - -int dhd_write_rdwr_macaddr(struct ether_addr *mac) -{ - char *filepath_data = MACINFO; - char *filepath_efs = MACINFO_EFS; - struct file *fp_mac = NULL; - char buf[18] = {0}; - mm_segment_t oldfs = {0}; - int ret = -1; - - if ((g_imac_flag != MACADDR_COB) && (g_imac_flag != MACADDR_MOD)) - return 0; - - sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X\n", - mac->octet[0], mac->octet[1], mac->octet[2], - mac->octet[3], mac->octet[4], mac->octet[5]); - - /* /data/.mac.info will be created */ - fp_mac = filp_open(filepath_data, O_RDWR | O_CREAT, 0666); - if (IS_ERR(fp_mac)) { - DHD_ERROR(("[WIFI] %s: File open error\n", filepath_data)); - return -1; - } else { - oldfs = get_fs(); - set_fs(get_ds()); - - if (fp_mac->f_mode & FMODE_WRITE) { - ret = fp_mac->f_op->write(fp_mac, (const char *)buf, - sizeof(buf), &fp_mac->f_pos); - if (ret < 0) - DHD_ERROR(("[WIFI] Mac address [%s] Failed" - " to write into File: %s\n", buf, filepath_data)); - else - DHD_INFO(("[WIFI] Mac address [%s] written" - " into File: %s\n", buf, filepath_data)); - } - set_fs(oldfs); - filp_close(fp_mac, NULL); - } - /* /efs/wifi/.mac.info will be created */ - fp_mac = filp_open(filepath_efs, O_RDWR | O_CREAT, 0666); - if (IS_ERR(fp_mac)) { - DHD_ERROR(("[WIFI] %s: File open error\n", filepath_efs)); - return -1; - } else { - oldfs = get_fs(); - set_fs(get_ds()); - - if (fp_mac->f_mode & FMODE_WRITE) { - ret = fp_mac->f_op->write(fp_mac, (const char *)buf, - sizeof(buf), &fp_mac->f_pos); - if (ret < 0) - DHD_ERROR(("[WIFI] Mac address [%s] Failed" - " to write into File: %s\n", buf, filepath_efs)); - else - DHD_INFO(("[WIFI] Mac address [%s] written" - " into File: %s\n", buf, filepath_efs)); - } - set_fs(oldfs); - filp_close(fp_mac, NULL); - } - - return 0; - -} - -int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, - struct ether_addr *mac) -{ - struct file *fp_mac = NULL; - struct file *fp_nvm = NULL; - char macbuffer[18] = {0}; - char randommac[3] = {0}; - char buf[18] = {0}; - char *filepath_data = MACINFO; - char *filepath_efs = MACINFO_EFS; -#ifdef CONFIG_TARGET_LOCALE_NA - char *nvfilepath = "/data/misc/wifi/.nvmac.info"; -#else - char *nvfilepath = NVMACINFO; -#endif - char cur_mac[128] = {0}; - char dummy_mac[ETHER_ADDR_LEN] = {0x00, 0x90, 0x4C, 0xC5, 0x12, 0x38}; - char cur_macbuffer[18] = {0}; - int ret = -1; - - g_imac_flag = MACADDR_NONE; - - fp_nvm = filp_open(nvfilepath, O_RDONLY, 0); - if (IS_ERR(fp_nvm)) { /* file does not exist */ - - /* Create the .nvmac.info */ - fp_nvm = filp_open(nvfilepath, O_RDWR | O_CREAT, 0666); - if (!IS_ERR(fp_nvm)) - filp_close(fp_nvm, NULL); - - /* read MAC Address */ - strcpy(cur_mac, "cur_etheraddr"); - ret = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, cur_mac, - sizeof(cur_mac), 0, 0); - if (ret < 0) { - DHD_ERROR(("Current READ MAC error \r\n")); - memset(cur_mac , 0 , ETHER_ADDR_LEN); - return -1; - } else { - DHD_ERROR(("MAC (OTP) : " - "[%02X:%02X:%02X:%02X:%02X:%02X] \r\n", - cur_mac[0], cur_mac[1], cur_mac[2], cur_mac[3], - cur_mac[4], cur_mac[5])); - } - - sprintf(cur_macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X\n", - cur_mac[0], cur_mac[1], cur_mac[2], - cur_mac[3], cur_mac[4], cur_mac[5]); - - fp_mac = filp_open(filepath_data, O_RDONLY, 0); - if (IS_ERR(fp_mac)) { /* file does not exist */ - /* read mac is the dummy mac (00:90:4C:C5:12:38) */ - if (memcmp(cur_mac, dummy_mac, ETHER_ADDR_LEN) == 0) - g_imac_flag = MACADDR_MOD_RANDOM; - else if (strncmp(buf, "00:00:00:00:00:00", 17) == 0) - g_imac_flag = MACADDR_MOD_RANDOM; - else - g_imac_flag = MACADDR_MOD; - } else { - int is_zeromac; - - ret = kernel_read(fp_mac, 0, buf, 18); - filp_close(fp_mac, NULL); - buf[17] = '\0'; - - is_zeromac = strncmp(buf, "00:00:00:00:00:00", 17); - DHD_ERROR(("MAC (FILE): [%s] [%d] \r\n", - buf, is_zeromac)); - - if (is_zeromac == 0) { - DHD_ERROR(("Zero MAC detected." - " Trying Random MAC.\n")); - g_imac_flag = MACADDR_MOD_RANDOM; - } else { - sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", - (unsigned int *)&(mac->octet[0]), - (unsigned int *)&(mac->octet[1]), - (unsigned int *)&(mac->octet[2]), - (unsigned int *)&(mac->octet[3]), - (unsigned int *)&(mac->octet[4]), - (unsigned int *)&(mac->octet[5])); - /* current MAC address is same as previous one */ - if(memcmp(cur_mac,mac->octet,ETHER_ADDR_LEN) == 0) { - g_imac_flag = MACADDR_NONE; - } else { /* change MAC address */ - if (0 == _dhd_set_mac_address(dhd, 0, mac)) { - DHD_INFO(("%s: MACID is" - " overwritten\n", __FUNCTION__)); - g_imac_flag = MACADDR_MOD; - } else { - DHD_ERROR(("%s: " - "_dhd_set_mac_address()" - " failed\n", __FUNCTION__)); - g_imac_flag = MACADDR_NONE; - } - } - } - } - fp_mac = filp_open(filepath_efs, O_RDONLY, 0); - if (IS_ERR(fp_mac)) { /* file does not exist */ - /* read mac is the dummy mac (00:90:4C:C5:12:38) */ - if (memcmp(cur_mac, dummy_mac, ETHER_ADDR_LEN) == 0) - g_imac_flag = MACADDR_MOD_RANDOM; - else if (strncmp(buf, "00:00:00:00:00:00", 17) == 0) - g_imac_flag = MACADDR_MOD_RANDOM; - else - g_imac_flag = MACADDR_MOD; - } else { - int is_zeromac; - - ret = kernel_read(fp_mac, 0, buf, 18); - filp_close(fp_mac, NULL); - buf[17] = '\0'; - - is_zeromac = strncmp(buf, "00:00:00:00:00:00", 17); - DHD_ERROR(("MAC (FILE): [%s] [%d] \r\n", - buf, is_zeromac)); - - if (is_zeromac == 0) { - DHD_ERROR(("Zero MAC detected." - " Trying Random MAC.\n")); - g_imac_flag = MACADDR_MOD_RANDOM; - } else { - sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", - (unsigned int *)&(mac->octet[0]), - (unsigned int *)&(mac->octet[1]), - (unsigned int *)&(mac->octet[2]), - (unsigned int *)&(mac->octet[3]), - (unsigned int *)&(mac->octet[4]), - (unsigned int *)&(mac->octet[5])); - /* current MAC address is same as previous one */ - if(memcmp(cur_mac,mac->octet,ETHER_ADDR_LEN) == 0) { - g_imac_flag = MACADDR_NONE; - } else { /* change MAC address */ - if (0 == _dhd_set_mac_address(dhd, 0, mac)) { - DHD_INFO(("%s: MACID is" - " overwritten\n", __FUNCTION__)); - g_imac_flag = MACADDR_MOD; - } else { - DHD_ERROR(("%s: " - "_dhd_set_mac_address()" - " failed\n", __FUNCTION__)); - g_imac_flag = MACADDR_NONE; - } - } - } - } - } else { - /* COB type. only COB. */ - /* Reading the MAC Address from .nvmac.info file - * (the existed file or just created file) - */ - ret = kernel_read(fp_nvm, 0, buf, 18); - - /* to prevent abnormal string display when mac address - * is displayed on the screen. - */ - buf[17] = '\0'; - DHD_ERROR(("Read MAC : [%s] [%d] \r\n", buf, - strncmp(buf, "00:00:00:00:00:00", 17))); - if ((buf[0] == '\0') || - (strncmp(buf, "00:00:00:00:00:00", 17) == 0)) { - g_imac_flag = MACADDR_COB_RANDOM; - } else { - sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", - (unsigned int *)&(mac->octet[0]), - (unsigned int *)&(mac->octet[1]), - (unsigned int *)&(mac->octet[2]), - (unsigned int *)&(mac->octet[3]), - (unsigned int *)&(mac->octet[4]), - (unsigned int *)&(mac->octet[5])); - /* Writing Newly generated MAC ID to the Dongle */ - if (0 == _dhd_set_mac_address(dhd, 0, mac)) { - DHD_INFO(("%s: MACID is overwritten\n", - __FUNCTION__)); - g_imac_flag = MACADDR_COB; - } else { - DHD_ERROR(("%s: _dhd_set_mac_address()" - " failed\n", __FUNCTION__)); - } - } - filp_close(fp_nvm, NULL); - } - - if ((g_imac_flag == MACADDR_COB_RANDOM) || - (g_imac_flag == MACADDR_MOD_RANDOM)) { - get_random_bytes(randommac, 3); - sprintf(macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X\n", - 0x60, 0xd0, 0xa9, randommac[0], randommac[1], - randommac[2]); - DHD_ERROR(("[WIFI] The Random Generated MAC ID : %s\n", - macbuffer)); - sscanf(macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X", - (unsigned int *)&(mac->octet[0]), - (unsigned int *)&(mac->octet[1]), - (unsigned int *)&(mac->octet[2]), - (unsigned int *)&(mac->octet[3]), - (unsigned int *)&(mac->octet[4]), - (unsigned int *)&(mac->octet[5])); - if (0 == _dhd_set_mac_address(dhd, 0, mac)) { - DHD_INFO(("%s: MACID is overwritten\n", __FUNCTION__)); - g_imac_flag = MACADDR_COB; - } else { - DHD_ERROR(("%s: _dhd_set_mac_address() failed\n", - __FUNCTION__)); - } - } - - return 0; -} -#endif /* RDWR_MACADDR */ - -#ifdef RDWR_KORICS_MACADDR -int dhd_write_rdwr_korics_macaddr(struct dhd_info *dhd, struct ether_addr *mac) -{ - struct file *fp = NULL; - char macbuffer[18] = {0}; - mm_segment_t oldfs = {0}; - char randommac[3] = {0}; - char buf[18] = {0}; - char *filepath_efs = MACINFO_EFS; - int is_zeromac = 0; - int ret = 0; - /* MAC address copied from efs/wifi.mac.info */ - fp = filp_open(filepath_efs, O_RDONLY, 0); - - if (IS_ERR(fp)) { - /* File Doesn't Exist. Create and write mac addr.*/ - fp = filp_open(filepath_efs, O_RDWR | O_CREAT, 0666); - if (IS_ERR(fp)) { - DHD_ERROR(("[WIFI] %s: File open error\n", - filepath_efs)); - return -1; - } - - oldfs = get_fs(); - set_fs(get_ds()); - - /* Generating the Random Bytes for - * 3 last octects of the MAC address - */ - get_random_bytes(randommac, 3); - - sprintf(macbuffer, "%02X:%02X:%02X:%02X:%02X:%02X\n", - 0x60, 0xd0, 0xa9, randommac[0], - randommac[1], randommac[2]); - DHD_ERROR(("[WIFI] The Random Generated MAC ID : %s\n", - macbuffer)); - - if (fp->f_mode & FMODE_WRITE) { - ret = fp->f_op->write(fp, - (const char *)macbuffer, - sizeof(macbuffer), &fp->f_pos); - if (ret < 0) - DHD_ERROR(("[WIFI] Mac address [%s]" - " Failed to write into File:" - " %s\n", macbuffer, filepath_efs)); - else - DHD_ERROR(("[WIFI] Mac address [%s]" - " written into File: %s\n", - macbuffer, filepath_efs)); - } - set_fs(oldfs); - } else { - /* Reading the MAC Address from .mac.info file - * (the existed file or just created file) - */ - ret = kernel_read(fp, 0, buf, 18); - /* to prevent abnormal string display when mac address - * is displayed on the screen. - */ - buf[17] = '\0'; - /* Remove security log */ - /*DHD_ERROR(("Read MAC : [%s] [%d] \r\n", buf, - strncmp(buf, "00:00:00:00:00:00", 17)));*/ - if ((buf[0] == '\0') || - (strncmp(buf, "00:00:00:00:00:00", 17) == 0)) { - is_zeromac = 1; - } - } - - if (ret) - sscanf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", - (unsigned int *)&(mac->octet[0]), - (unsigned int *)&(mac->octet[1]), - (unsigned int *)&(mac->octet[2]), - (unsigned int *)&(mac->octet[3]), - (unsigned int *)&(mac->octet[4]), - (unsigned int *)&(mac->octet[5])); - else - DHD_INFO(("dhd_bus_start: Reading from the" - " '%s' returns 0 bytes\n", filepath_efs)); - - if (fp) - filp_close(fp, NULL); - - if (!is_zeromac) { - /* Writing Newly generated MAC ID to the Dongle */ - if (0 == _dhd_set_mac_address(dhd, 0, mac)) - DHD_INFO(("dhd_bus_start: MACID is overwritten\n")); - else - DHD_ERROR(("dhd_bus_start: _dhd_set_mac_address() " - "failed\n")); - } else { - DHD_ERROR(("dhd_bus_start:Is ZeroMAC BypassWrite.mac.info!\n")); - } - - return 0; -} -#endif /* RDWR_KORICS_MACADDR */ - -#ifdef USE_CID_CHECK -static int dhd_write_cid_file(const char *filepath_efs, const char *buf, int buf_len) -{ - struct file *fp = NULL; - mm_segment_t oldfs = {0}; - int ret = 0; - - /* File is always created.*/ - fp = filp_open(filepath_efs, O_RDWR | O_CREAT, 0666); - if (IS_ERR(fp)) { - DHD_ERROR(("[WIFI] %s: File open error\n", filepath_efs)); - return -1; - } else { - oldfs = get_fs(); - set_fs(get_ds()); - - if (fp->f_mode & FMODE_WRITE) { - ret = fp->f_op->write(fp, buf, buf_len, &fp->f_pos); - if (ret < 0) - DHD_ERROR(("[WIFI] Failed to write CIS[%s]" - " into '%s'\n", buf, filepath_efs)); - else - DHD_ERROR(("[WIFI] CID [%s] written into" - " '%s'\n", buf, filepath_efs)); - } - set_fs(oldfs); - } - filp_close(fp, NULL); - - return 0; -} - -#ifdef DUMP_CIS -static void dhd_dump_cis(const unsigned char *buf, int size) -{ - int i; - for (i = 0; i < size; i++) { - DHD_ERROR(("%02X ", buf[i])); - if ((i % 15) == 15) DHD_ERROR(("\n")); - } - DHD_ERROR(("\n")); -} -#endif /* DUMP_CIS */ - -#ifdef BCM4334_CHIP -#define CIS_CID_OFFSET 43 -#else -#define CIS_CID_OFFSET 31 -#endif /* BCM4334_CHIP */ - -int dhd_check_module_cid(dhd_pub_t *dhd) -{ - int ret = -1; -#ifdef BCM4334_CHIP - unsigned char cis_buf[250] = {0}; - const char *revfilepath = REVINFO; - int flag_b3 = 0; -#else - unsigned char cis_buf[128] = {0}; -#endif - const char *cidfilepath = CIDINFO; - - /* Try reading out from CIS */ - cis_rw_t *cish = (cis_rw_t *)&cis_buf[8]; - - cish->source = 0; - cish->byteoff = 0; - cish->nbytes = sizeof(cis_buf); - - strcpy(cis_buf, "cisdump"); - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cis_buf, - sizeof(cis_buf), 0, 0); - if (ret < 0) { - DHD_TRACE(("%s: CIS reading failed, err=%d\n", - __FUNCTION__, ret)); - return ret; - } else { -#ifdef BCM4334_CHIP - unsigned char semco_id[4] = {0x00, 0x00, 0x33, 0x33}; - unsigned char semco_id_sh[4] = {0x00, 0x00, 0xFB, 0x50}; //for SHARP FEM(new) - DHD_ERROR(("%s: CIS reading success, ret=%d\n", - __FUNCTION__, ret)); -#ifdef DUMP_CIS - dump_cis(cis_buf, 48); -#endif - if (memcmp(&cis_buf[CIS_CID_OFFSET], semco_id, 4) == 0) { - DHD_ERROR(("CID MATCH FOUND : Semco, 0x%02X 0x%02X \ - 0x%02X 0x%02X\n", cis_buf[CIS_CID_OFFSET], - cis_buf[CIS_CID_OFFSET+1], cis_buf[CIS_CID_OFFSET+2], - cis_buf[CIS_CID_OFFSET+3])); - dhd_write_cid_file(cidfilepath, "semco", 5); - } else if (memcmp(&cis_buf[CIS_CID_OFFSET], semco_id_sh, 4) == 0) { - DHD_ERROR(("CIS MATCH FOUND : Semco_sh, 0x%02X 0x%02X \ - 0x%02X 0x%02X\n", cis_buf[CIS_CID_OFFSET], - cis_buf[CIS_CID_OFFSET+1], cis_buf[CIS_CID_OFFSET+2], - cis_buf[CIS_CID_OFFSET+3])); - dhd_write_cid_file(cidfilepath, "semcosh", 7); - } else { - DHD_ERROR(("CID MATCH FOUND : Murata, 0x%02X 0x%02X \ - 0x%02X 0x%02X\n", cis_buf[CIS_CID_OFFSET], - cis_buf[CIS_CID_OFFSET+1], cis_buf[CIS_CID_OFFSET+2], - cis_buf[CIS_CID_OFFSET+3])); - dhd_write_cid_file(cidfilepath, "murata", 6); - } - - /* Try reading out from OTP to distinguish B2 or B3 */ - memset(cis_buf, 0, sizeof(cis_buf)); - cish = (cis_rw_t *)&cis_buf[8]; - - cish->source = 0; - cish->byteoff = 0; - cish->nbytes = sizeof(cis_buf); - - strcpy(cis_buf, "otpdump"); - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cis_buf, - sizeof(cis_buf), 0, 0); - if (ret < 0) { - DHD_ERROR(("%s: OTP reading failed, err=%d\n", - __FUNCTION__, ret)); - return ret; - } - - /* otp 33th character is identifier for 4334B3 */ - cis_buf[34] = '\0'; - flag_b3 = bcm_atoi(&cis_buf[33]); - if(flag_b3 & 0x1){ - DHD_ERROR(("REV MATCH FOUND : 4334B3, %c\n", cis_buf[33])); - dhd_write_cid_file(revfilepath, "4334B3", 6); - } - -#else /* BCM4330_CHIP */ - unsigned char murata_id[4] = {0x80, 0x06, 0x81, 0x00}; - unsigned char semco_ve[4] = {0x80, 0x02, 0x81, 0x99}; -#ifdef DUMP_CIS - dhd_dump_cis(cis_buf, 48); -#endif - if (memcmp(&cis_buf[CIS_CID_OFFSET], murata_id, 4) == 0) { - DHD_ERROR(("CID MATCH FOUND : Murata\n")); - dhd_write_cid_file(cidfilepath, "murata", 6); - } else if (memcmp(&cis_buf[CIS_CID_OFFSET], semco_ve, 4) - == 0) { - DHD_ERROR(("CID MATCH FOUND : Semco VE\n")); - dhd_write_cid_file(cidfilepath, "semcove", 7); - } else { - DHD_ERROR(("CID MISMATCH" - " 0x%02X 0x%02X 0x%02X 0x%02X\n", - cis_buf[CIS_CID_OFFSET], - cis_buf[CIS_CID_OFFSET + 1], - cis_buf[CIS_CID_OFFSET + 2], - cis_buf[CIS_CID_OFFSET + 3])); - dhd_write_cid_file(cidfilepath, "samsung", 7); - } -#endif /* BCM4334_CHIP */ - DHD_ERROR(("%s: CIS write success, err=%d\n", - __FUNCTION__, ret)); - } - - return ret; -} -#endif /* USE_CID_CHECK */ - -#ifdef GET_MAC_FROM_OTP -static int dhd_write_mac_file(const char *filepath, const char *buf, int buf_len) -{ - struct file *fp = NULL; - mm_segment_t oldfs = {0}; - int ret = 0; - - fp = filp_open(filepath, O_RDWR | O_CREAT, 0666); - /*File is always created.*/ - if (IS_ERR(fp)) { - DHD_ERROR(("[WIFI] File open error\n")); - return -1; - } else { - oldfs = get_fs(); - set_fs(get_ds()); - - if (fp->f_mode & FMODE_WRITE) { - ret = fp->f_op->write(fp, buf, buf_len, &fp->f_pos); - if (ret < 0) - DHD_ERROR(("[WIFI] Failed to write CIS. \n")); - else - DHD_ERROR(("[WIFI] MAC written. \n")); - } - set_fs(oldfs); - } - filp_close(fp, NULL); - - return 0; -} - -#define CIS_MAC_OFFSET 33 - -int dhd_check_module_mac(dhd_pub_t *dhd) -{ - int ret = -1; - unsigned char cis_buf[250] = {0}; - unsigned char mac_buf[20] = {0}; - unsigned char otp_mac_buf[20] = {0}; - const char *macfilepath = MACINFO_EFS; - - /* Try reading out from CIS */ - cis_rw_t *cish = (cis_rw_t *)&cis_buf[8]; - struct file *fp_mac = NULL; - - cish->source = 0; - cish->byteoff = 0; - cish->nbytes = sizeof(cis_buf); - - strcpy(cis_buf, "cisdump"); - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, cis_buf, - sizeof(cis_buf), 0, 0); - if (ret < 0) { - DHD_TRACE(("%s: CIS reading failed, err=%d\n", __func__, - ret)); - return ret; - } else { - unsigned char mac_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -#ifdef DUMP_CIS - dump_cis(cis_buf, 48); -#endif - mac_id[0] = cis_buf[CIS_MAC_OFFSET]; - mac_id[1] = cis_buf[CIS_MAC_OFFSET + 1]; - mac_id[2] = cis_buf[CIS_MAC_OFFSET + 2]; - mac_id[3] = cis_buf[CIS_MAC_OFFSET + 3]; - mac_id[4] = cis_buf[CIS_MAC_OFFSET + 4]; - mac_id[5] = cis_buf[CIS_MAC_OFFSET + 5]; - - sprintf(otp_mac_buf, "%02X:%02X:%02X:%02X:%02X:%02X\n", - mac_id[0], mac_id[1], mac_id[2], mac_id[3], mac_id[4], - mac_id[5]); - DHD_ERROR(("[WIFI]mac_id is setted from OTP \n")); - } - - fp_mac = filp_open(macfilepath, O_RDONLY, 0); - if (!IS_ERR(fp_mac)) { - DHD_ERROR(("[WIFI]Check Mac address in .mac.info \n")); - kernel_read(fp_mac, fp_mac->f_pos, mac_buf, sizeof(mac_buf)); - - if (strncmp(mac_buf , otp_mac_buf , 17) != 0) { - DHD_ERROR(("[WIFI]file MAC is wrong. Write OTP MAC in .mac.info \n")); - dhd_write_mac_file(macfilepath, otp_mac_buf, sizeof(otp_mac_buf)); - } - } - - return ret; -} -#endif /* GET_MAC_FROM_OTP */ - -#ifdef WRITE_MACADDR -int dhd_write_macaddr(struct ether_addr *mac) -{ - char *filepath_data = MACINFO; - char *filepath_efs = MACINFO_EFS; - - struct file *fp_mac = NULL; - char buf[18] = {0}; - mm_segment_t oldfs = {0}; - int ret = -1; - int retry_count = 0; - -startwrite: - - sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X\n", - mac->octet[0], mac->octet[1], mac->octet[2], - mac->octet[3], mac->octet[4], mac->octet[5]); - - /* File will be created /data/.mac.info. */ - fp_mac = filp_open(filepath_data, O_RDWR | O_CREAT, 0666); - - if (IS_ERR(fp_mac)) { - DHD_ERROR(("[WIFI] %s: File open error\n", filepath_data)); - return -1; - } else { - oldfs = get_fs(); - set_fs(get_ds()); - - if (fp_mac->f_mode & FMODE_WRITE) { - ret = fp_mac->f_op->write(fp_mac, (const char *)buf, - sizeof(buf), &fp_mac->f_pos); - if (ret < 0) - DHD_ERROR(("[WIFI] Mac address [%s] Failed to" - " write into File: %s\n", buf, filepath_data)); - else - DHD_INFO(("[WIFI] Mac address [%s] written" - " into File: %s\n", buf, filepath_data)); - } - set_fs(oldfs); - filp_close(fp_mac, NULL); - } - /* check .mac.info file is 0 byte */ - fp_mac = filp_open(filepath_data, O_RDONLY, 0); - ret = kernel_read(fp_mac, 0, buf, 18); - - if ((ret == 0) && (retry_count++ < 3)) { - filp_close(fp_mac, NULL); - goto startwrite; - } - - filp_close(fp_mac, NULL); - /* end of /data/.mac.info */ - - if (filepath_efs == NULL) { - DHD_ERROR(("[WIFI]%s : no efs filepath", __func__)); - return 0; - } - - /* File will be created /efs/wifi/.mac.info. */ - fp_mac = filp_open(filepath_efs, O_RDWR | O_CREAT, 0666); - - if (IS_ERR(fp_mac)) { - DHD_ERROR(("[WIFI] %s: File open error\n", filepath_efs)); - return -1; - } else { - oldfs = get_fs(); - set_fs(get_ds()); - - if (fp_mac->f_mode & FMODE_WRITE) { - ret = fp_mac->f_op->write(fp_mac, (const char *)buf, - sizeof(buf), &fp_mac->f_pos); - if (ret < 0) - DHD_ERROR(("[WIFI] Mac address [%s] Failed to" - " write into File: %s\n", buf, filepath_efs)); - else - DHD_INFO(("[WIFI] Mac address [%s] written" - " into File: %s\n", buf, filepath_efs)); - } - set_fs(oldfs); - filp_close(fp_mac, NULL); - } - - /* check .mac.info file is 0 byte */ - fp_mac = filp_open(filepath_efs, O_RDONLY, 0); - ret = kernel_read(fp_mac, 0, buf, 18); - - if ((ret == 0) && (retry_count++ < 3)) { - filp_close(fp_mac, NULL); - goto startwrite; - } - - filp_close(fp_mac, NULL); - - return 0; -} -#endif /* WRITE_MACADDR */ - -#ifdef CONFIG_CONTROL_PM -extern bool g_pm_control; -void sec_control_pm(dhd_pub_t *dhd, uint *power_mode) -{ - struct file *fp = NULL; - char *filepath = PSMINFO; - mm_segment_t oldfs = {0}; - char power_val = 0; - char iovbuf[WL_EVENTING_MASK_LEN + 12]; - - g_pm_control = FALSE; - - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { - /* Enable PowerSave Mode */ - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)power_mode, - sizeof(uint), TRUE, 0); - - fp = filp_open(filepath, O_RDWR | O_CREAT, 0666); - if (IS_ERR(fp) || (fp == NULL)) { - DHD_ERROR(("[%s, %d] /data/.psm.info open failed\n", - __FUNCTION__, __LINE__)); - return; - } else { - oldfs = get_fs(); - set_fs(get_ds()); - - if (fp->f_mode & FMODE_WRITE) { - power_val = '1'; - fp->f_op->write(fp, (const char *)&power_val, - sizeof(char), &fp->f_pos); - } - set_fs(oldfs); - } - } else { - kernel_read(fp, fp->f_pos, &power_val, 1); - DHD_ERROR(("POWER_VAL = %c \r\n" , power_val)); - - if (power_val == '0') { -#ifdef ROAM_ENABLE - uint roamvar = 1; -#endif - *power_mode = PM_OFF; - /* Disable PowerSave Mode */ - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)power_mode, - sizeof(uint), TRUE, 0); - /* Turn off MPC in AP mode */ - bcm_mkiovar("mpc", (char *)power_mode, 4, - iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0); - g_pm_control = TRUE; -#ifdef ROAM_ENABLE - /* Roaming off of dongle */ - bcm_mkiovar("roam_off", (char *)&roamvar, 4, - iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0); -#endif - } else { - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)power_mode, - sizeof(uint), TRUE, 0); - } - } - - if (fp) - filp_close(fp, NULL); -} -#endif -#ifdef GLOBALCONFIG_WLAN_COUNTRY_CODE -int dhd_customer_set_country(dhd_pub_t *dhd) -{ - struct file *fp = NULL; - char *filepath = "/data/.ccode.info"; - char iovbuf[WL_EVENTING_MASK_LEN + 12] = {0}; - char buffer[10] = {0}; - int ret = 0; - wl_country_t cspec; - int buf_len = 0; - char country_code[WLC_CNTRY_BUF_SZ]; - int country_rev; - int country_offset; - int country_code_size; - char country_rev_buf[WLC_CNTRY_BUF_SZ]; - fp = filp_open(filepath, O_RDONLY, 0); - if (IS_ERR(fp)) { - DHD_ERROR(("%s: %s open failed\n", __FUNCTION__, filepath)); - return -1; - } else { - if (kernel_read(fp, 0, buffer, sizeof(buffer))) { - memset(&cspec, 0, sizeof(cspec)); - memset(country_code, 0, sizeof(country_code)); - memset(country_rev_buf, 0, sizeof(country_rev_buf)); - country_offset = strcspn(buffer, " "); - country_code_size = country_offset; - if (country_offset != 0) { - strncpy(country_code, buffer, country_offset); - strncpy(country_rev_buf, buffer+country_offset+1, strlen(buffer) - country_code_size + 1); - country_rev = bcm_atoi(country_rev_buf); - buf_len = bcm_mkiovar("country", (char *)&cspec, sizeof(cspec), iovbuf, sizeof(iovbuf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, buf_len, FALSE, 0); - memcpy((void *)&cspec, iovbuf, sizeof(cspec)); - if (!ret) { - DHD_ERROR(("%s: get country ccode:%s country_abrev:%s rev:%d \n", __FUNCTION__, cspec.ccode, cspec.country_abbrev, cspec.rev)); - if ((strncmp(country_code, cspec.ccode, WLC_CNTRY_BUF_SZ) != 0) || (cspec.rev != country_rev)) { - strncpy(cspec.country_abbrev, country_code, country_code_size); - strncpy(cspec.ccode, country_code, country_code_size); - cspec.rev = country_rev; - DHD_ERROR(("%s: set country ccode:%s country_abrev:%s rev:%d \n", __FUNCTION__, cspec.ccode, cspec.country_abbrev, cspec.rev)); - buf_len = bcm_mkiovar("country", (char *)&cspec, sizeof(cspec), iovbuf, sizeof(iovbuf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, buf_len, TRUE, 0); - } - } - } else { - DHD_ERROR(("%s: set country %s failed code \n", __FUNCTION__, country_code)); - ret = -1; - } - } else { - DHD_ERROR(("%s: Reading from the '%s' returns 0 bytes \n", __FUNCTION__, filepath)); - ret = -1; - } - } - if (fp) - filp_close(fp, NULL); - - return ret; -} -#endif diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_dbg.h b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_dbg.h deleted file mode 100644 index ac0713b..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_dbg.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Debug/trace/assert driver definitions for Dongle Host Driver. - * - * Copyright (C) 1999-2011, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_dbg.h 303834 2011-12-20 06:17:39Z $ - */ - -#ifndef _dhd_dbg_ -#define _dhd_dbg_ - -#if defined(DHD_DEBUG) - -#define DHD_ERROR(args) do {if (dhd_msg_level & DHD_ERROR_VAL) printf args;} while (0) -#define DHD_TRACE(args) do {if (dhd_msg_level & DHD_TRACE_VAL) printf args;} while (0) -#define DHD_INFO(args) do {if (dhd_msg_level & DHD_INFO_VAL) printf args;} while (0) -#define DHD_DATA(args) do {if (dhd_msg_level & DHD_DATA_VAL) printf args;} while (0) -#define DHD_CTL(args) do {if (dhd_msg_level & DHD_CTL_VAL) printf args;} while (0) -#define DHD_TIMER(args) do {if (dhd_msg_level & DHD_TIMER_VAL) printf args;} while (0) -#define DHD_HDRS(args) do {if (dhd_msg_level & DHD_HDRS_VAL) printf args;} while (0) -#define DHD_BYTES(args) do {if (dhd_msg_level & DHD_BYTES_VAL) printf args;} while (0) -#define DHD_INTR(args) do {if (dhd_msg_level & DHD_INTR_VAL) printf args;} while (0) -#define DHD_GLOM(args) do {if (dhd_msg_level & DHD_GLOM_VAL) printf args;} while (0) -#define DHD_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0) -#define DHD_BTA(args) do {if (dhd_msg_level & DHD_BTA_VAL) printf args;} while (0) -#define DHD_ISCAN(args) do {if (dhd_msg_level & DHD_ISCAN_VAL) printf args;} while (0) -#define DHD_ARPOE(args) do {if (dhd_msg_level & DHD_ARPOE_VAL) printf args;} while (0) -#define DHD_REORDER(args) do {if (dhd_msg_level & DHD_REORDER_VAL) printf args;} while (0) - -#define DHD_ERROR_ON() (dhd_msg_level & DHD_ERROR_VAL) -#define DHD_TRACE_ON() (dhd_msg_level & DHD_TRACE_VAL) -#define DHD_INFO_ON() (dhd_msg_level & DHD_INFO_VAL) -#define DHD_DATA_ON() (dhd_msg_level & DHD_DATA_VAL) -#define DHD_CTL_ON() (dhd_msg_level & DHD_CTL_VAL) -#define DHD_TIMER_ON() (dhd_msg_level & DHD_TIMER_VAL) -#define DHD_HDRS_ON() (dhd_msg_level & DHD_HDRS_VAL) -#define DHD_BYTES_ON() (dhd_msg_level & DHD_BYTES_VAL) -#define DHD_INTR_ON() (dhd_msg_level & DHD_INTR_VAL) -#define DHD_GLOM_ON() (dhd_msg_level & DHD_GLOM_VAL) -#define DHD_EVENT_ON() (dhd_msg_level & DHD_EVENT_VAL) -#define DHD_BTA_ON() (dhd_msg_level & DHD_BTA_VAL) -#define DHD_ISCAN_ON() (dhd_msg_level & DHD_ISCAN_VAL) -#define DHD_ARPOE_ON() (dhd_msg_level & DHD_ARPOE_VAL) -#define DHD_REORDER_ON() (dhd_msg_level & DHD_REORDER_VAL) - -#else /* defined(BCMDBG) || defined(DHD_DEBUG) */ - -#define DHD_ERROR(args) do {if (net_ratelimit()) printf args;} while (0) -#define DHD_TRACE(args) -#define DHD_INFO(args) -#define DHD_DATA(args) -#define DHD_CTL(args) -#define DHD_TIMER(args) -#define DHD_HDRS(args) -#define DHD_BYTES(args) -#define DHD_INTR(args) -#define DHD_GLOM(args) -#define DHD_EVENT(args) -#define DHD_BTA(args) -#define DHD_ISCAN(args) -#define DHD_ARPOE(args) -#define DHD_REORDER(args) - -#define DHD_ERROR_ON() 0 -#define DHD_TRACE_ON() 0 -#define DHD_INFO_ON() 0 -#define DHD_DATA_ON() 0 -#define DHD_CTL_ON() 0 -#define DHD_TIMER_ON() 0 -#define DHD_HDRS_ON() 0 -#define DHD_BYTES_ON() 0 -#define DHD_INTR_ON() 0 -#define DHD_GLOM_ON() 0 -#define DHD_EVENT_ON() 0 -#define DHD_BTA_ON() 0 -#define DHD_ISCAN_ON() 0 -#define DHD_ARPOE_ON() 0 -#define DHD_REORDER_ON() 0 -#endif - -#define DHD_LOG(args) - -#define DHD_BLOG(cp, size) - -#define DHD_NONE(args) -extern int dhd_msg_level; - -/* Defines msg bits */ -#include <dhdioctl.h> - -#endif /* _dhd_dbg_ */ diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_linux.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_linux.c deleted file mode 100644 index da72c75..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_linux.c +++ /dev/null @@ -1,6027 +0,0 @@ -/* - * Broadcom Dongle Host Driver (DHD), Linux-specific network interface - * Basically selected code segments from usb-cdc.c and usb-rndis.c - * - * Copyright (C) 1999-2012, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux.c 309571 2012-01-20 01:45:10Z $ - */ - -#include <typedefs.h> -#include <linuxver.h> -#include <osl.h> - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/inetdevice.h> -#include <linux/rtnetlink.h> -#include <linux/etherdevice.h> -#include <linux/random.h> -#include <linux/spinlock.h> -#include <linux/ethtool.h> -#include <linux/fcntl.h> -#include <linux/fs.h> - -#include <asm/uaccess.h> -#include <asm/unaligned.h> - -#include <epivers.h> -#include <bcmutils.h> -#include <bcmendian.h> - -#include <proto/ethernet.h> -#include <dngl_stats.h> -#include <dhd.h> -#include <dhd_bus.h> -#include <dhd_proto.h> -#include <dhd_dbg.h> -#ifdef CONFIG_HAS_WAKELOCK -#include <linux/wakelock.h> -#endif -#ifdef WL_CFG80211 -#include <wl_cfg80211.h> -#endif - -#ifdef WLBTAMP -#include <proto/802.11_bta.h> -#include <proto/bt_amp_hci.h> -#include <dhd_bta.h> -#endif - -#ifdef WLMEDIA_HTSF -#include <linux/time.h> -#include <htsf.h> - -#define HTSF_MINLEN 200 /* min. packet length to timestamp */ -#define HTSF_BUS_DELAY 150 /* assume a fix propagation in us */ -#define TSMAX 1000 /* max no. of timing record kept */ -#define NUMBIN 34 - -static uint32 tsidx = 0; -static uint32 htsf_seqnum = 0; -uint32 tsfsync; -struct timeval tsync; -static uint32 tsport = 5010; - -typedef struct histo_ { - uint32 bin[NUMBIN]; -} histo_t; - -#if !ISPOWEROF2(DHD_SDALIGN) -#error DHD_SDALIGN is not a power of 2! -#endif - -static histo_t vi_d1, vi_d2, vi_d3, vi_d4; -#endif /* WLMEDIA_HTSF */ - -#if defined(SOFTAP) -extern bool ap_cfg_running; -extern bool ap_fw_loaded; -#endif - -/* enable HOSTIP cache update from the host side when an eth0:N is up */ -#define AOE_IP_ALIAS_SUPPORT 1 - -#ifdef BCM_FD_AGGR -#include <bcm_rpc.h> -#include <bcm_rpc_tp.h> -#endif -#ifdef PROP_TXSTATUS -#include <wlfc_proto.h> -#include <dhd_wlfc.h> -#endif - -#include <wl_android.h> - -#ifdef ARP_OFFLOAD_SUPPORT -void aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add); -static int dhd_device_event(struct notifier_block *this, - unsigned long event, - void *ptr); - -static struct notifier_block dhd_notifier = { - .notifier_call = dhd_device_event -}; -#endif /* ARP_OFFLOAD_SUPPORT */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -#include <linux/suspend.h> -volatile bool dhd_mmc_suspend = FALSE; -DECLARE_WAIT_QUEUE_HEAD(dhd_dpc_wait); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - -#if defined(OOB_INTR_ONLY) -extern void dhd_enable_oob_intr(struct dhd_bus *bus, bool enable); -#endif /* defined(OOB_INTR_ONLY) */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -MODULE_LICENSE("GPL v2"); -#endif /* LinuxVer */ - -#include <dhd_bus.h> - -#ifdef BCM_FD_AGGR -#define DBUS_RX_BUFFER_SIZE_DHD(net) (BCM_RPC_TP_DNGL_AGG_MAX_BYTE) -#else -#ifndef PROP_TXSTATUS -#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen) -#else -#define DBUS_RX_BUFFER_SIZE_DHD(net) (net->mtu + net->hard_header_len + dhd->pub.hdrlen + 128) -#endif -#endif /* BCM_FD_AGGR */ - -#if LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) -const char * -print_tainted() -{ - return ""; -} -#endif /* LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 15) */ - -/* Linux wireless extension support */ -#if defined(CONFIG_WIRELESS_EXT) -#include <wl_iw.h> -extern wl_iw_extra_params_t g_wl_iw_params; -#endif /* defined(CONFIG_WIRELESS_EXT) */ - -#if defined(CONFIG_HAS_EARLYSUSPEND) -#include <linux/earlysuspend.h> -extern int dhdcdc_set_ioctl(dhd_pub_t *dhd, int ifidx, uint cmd, void *buf, uint len); -extern int dhd_get_dtim_skip(dhd_pub_t *dhd); -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ - -#ifdef PKT_FILTER_SUPPORT -extern void dhd_pktfilter_offload_set(dhd_pub_t * dhd, char *arg); -extern void dhd_pktfilter_offload_enable(dhd_pub_t * dhd, char *arg, int enable, int master_mode); -#endif - -#ifdef CUSTOMER_HW_SAMSUNG -#ifdef READ_MACADDR -extern int dhd_read_macaddr(struct dhd_info *dhd, struct ether_addr *mac); -#endif -#ifdef RDWR_MACADDR -extern int dhd_check_rdwr_macaddr(struct dhd_info *dhd, dhd_pub_t *dhdp, struct ether_addr *mac); -extern int dhd_write_rdwr_macaddr(struct ether_addr *mac); -#endif -#ifdef WRITE_MACADDR -extern int dhd_write_macaddr(struct ether_addr *mac); -#endif -#ifdef USE_CID_CHECK -extern int dhd_check_module_cid(dhd_pub_t *dhd); -#endif -#ifdef GET_MAC_FROM_OTP -extern int dhd_check_module_mac(dhd_pub_t *dhd); -#endif -#endif /* CUSTOMER_HW_SAMSUNG */ - -#ifdef GLOBALCONFIG_WLAN_COUNTRY_CODE -int dhd_customer_set_country(dhd_pub_t *dhd); -#endif - -/* Interface control information */ -typedef struct dhd_if { - struct dhd_info *info; /* back pointer to dhd_info */ - /* OS/stack specifics */ - struct net_device *net; - struct net_device_stats stats; - int idx; /* iface idx in dongle */ - dhd_if_state_t state; /* interface state */ - uint subunit; /* subunit */ - uint8 mac_addr[ETHER_ADDR_LEN]; /* assigned MAC address */ - bool attached; /* Delayed attachment when unset */ - bool txflowcontrol; /* Per interface flow control indicator */ - char name[IFNAMSIZ+1]; /* linux interface name */ - uint8 bssidx; /* bsscfg index for the interface */ - bool set_multicast; - bool event2cfg80211; /* To determine if pass event to cfg80211 */ -} dhd_if_t; - -#ifdef WLMEDIA_HTSF -typedef struct { - uint32 low; - uint32 high; -} tsf_t; - -typedef struct { - uint32 last_cycle; - uint32 last_sec; - uint32 last_tsf; - uint32 coef; /* scaling factor */ - uint32 coefdec1; /* first decimal */ - uint32 coefdec2; /* second decimal */ -} htsf_t; - -typedef struct { - uint32 t1; - uint32 t2; - uint32 t3; - uint32 t4; -} tstamp_t; - -static tstamp_t ts[TSMAX]; -static tstamp_t maxdelayts; -static uint32 maxdelay = 0, tspktcnt = 0, maxdelaypktno = 0; - -#endif /* WLMEDIA_HTSF */ - -#if defined(CONFIG_PM_SLEEP) && defined(CUSTOMER_HW_SLP) -/*SLP_wakelock_alternative_code*/ -extern struct device *pm_dev; -#endif /* CONFIG_PM_SLEEP && CUSTOMER_HW_SLP */ -#if defined(PKT_FILTER_SUPPORT) -#if defined(CUSTOMER_HW_SAMSUNG) -#define HEX_PREF_STR "0x" -#define UNI_FILTER_STR "010000000000" -#define ZERO_ADDR_STR "000000000000" -#define ETHER_TYPE_STR "0000" -#define IPV6_FILTER_STR "20" -#define ZERO_TYPE_STR "00" -#endif /* CUSTOMER_HW_SAMSUNG */ -#endif /* PKT_FILTER_SUPPORT */ -/* Local private structure (extension of pub) */ -typedef struct dhd_info { -#if defined(CONFIG_WIRELESS_EXT) - wl_iw_t iw; /* wireless extensions state (must be first) */ -#endif /* defined(CONFIG_WIRELESS_EXT) */ - - dhd_pub_t pub; - - /* For supporting multiple interfaces */ - dhd_if_t *iflist[DHD_MAX_IFS]; - - struct semaphore proto_sem; -#ifdef PROP_TXSTATUS - spinlock_t wlfc_spinlock; -#endif /* PROP_TXSTATUS */ -#ifdef WLMEDIA_HTSF - htsf_t htsf; -#endif - wait_queue_head_t ioctl_resp_wait; - struct timer_list timer; - bool wd_timer_valid; - struct tasklet_struct tasklet; - spinlock_t sdlock; - spinlock_t txqlock; - spinlock_t dhd_lock; -#ifdef DHDTHREAD - /* Thread based operation */ - bool threads_only; - struct semaphore sdsem; - - tsk_ctl_t thr_dpc_ctl; - tsk_ctl_t thr_wdt_ctl; - -#else - bool dhd_tasklet_create; -#endif /* DHDTHREAD */ - tsk_ctl_t thr_sysioc_ctl; - - /* Wakelocks */ -#if defined(CONFIG_HAS_WAKELOCK) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - struct wake_lock wl_wifi; /* Wifi wakelock */ - struct wake_lock wl_rxwake; /* Wifi rx wakelock */ -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - /* net_device interface lock, prevent race conditions among net_dev interface - * calls and wifi_on or wifi_off - */ - struct mutex dhd_net_if_mutex; -#endif - spinlock_t wakelock_spinlock; - int wakelock_counter; - int wakelock_timeout_enable; - - /* Thread to issue ioctl for multicast */ - unsigned char set_macaddress; - struct ether_addr macvalue; - wait_queue_head_t ctrl_wait; - atomic_t pend_8021x_cnt; - dhd_attach_states_t dhd_state; - -#ifdef CONFIG_HAS_EARLYSUSPEND - struct early_suspend early_suspend; -#endif /* CONFIG_HAS_EARLYSUSPEND */ - -#ifdef ARP_OFFLOAD_SUPPORT - u32 pend_ipaddr; -#endif /* ARP_OFFLOAD_SUPPORT */ -#ifdef BCM_FD_AGGR - void *rpc_th; - void *rpc_osh; - struct timer_list rpcth_timer; - bool rpcth_timer_active; -#endif -} dhd_info_t; - -/* Definitions to provide path to the firmware and nvram - * example nvram_path[MOD_PARAM_PATHLEN]="/projects/wlan/nvram.txt" - */ -char firmware_path[MOD_PARAM_PATHLEN]; -char nvram_path[MOD_PARAM_PATHLEN]; - -int op_mode = 0; -int disable_proptx = 0; -module_param(op_mode, int, 0644); -extern int wl_control_wl_start(struct net_device *dev); -extern int net_os_send_hang_message(struct net_device *dev); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -struct semaphore dhd_registration_sem; -struct semaphore dhd_chipup_sem; -int dhd_registration_check = FALSE; - -#define DHD_REGISTRATION_TIMEOUT 12000 /* msec : allowed time to finished dhd registration */ -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ - -/* Spawn a thread for system ioctls (set mac, set mcast) */ -uint dhd_sysioc = TRUE; -module_param(dhd_sysioc, uint, 0); - -/* Error bits */ -module_param(dhd_msg_level, int, 0); -module_param(disable_proptx, int, 0); - -/* load firmware and/or nvram values from the filesystem */ -module_param_string(firmware_path, firmware_path, MOD_PARAM_PATHLEN, 0660); -module_param_string(nvram_path, nvram_path, MOD_PARAM_PATHLEN, 0); - -/* Watchdog interval */ -uint dhd_watchdog_ms = 10; -module_param(dhd_watchdog_ms, uint, 0); - -#if defined(DHD_DEBUG) -/* Console poll interval */ -uint dhd_console_ms = 0; -module_param(dhd_console_ms, uint, 0644); -#endif /* defined(DHD_DEBUG) */ - -uint dhd_slpauto = TRUE; -module_param(dhd_slpauto, uint, 0); - -/* ARP offload agent mode : Enable ARP Host Auto-Reply and ARP Peer Auto-Reply */ -uint dhd_arp_mode = 0xb; -module_param(dhd_arp_mode, uint, 0); - -/* ARP offload enable */ -uint dhd_arp_enable = TRUE; -module_param(dhd_arp_enable, uint, 0); - -/* Global Pkt filter enable control */ -uint dhd_pkt_filter_enable = TRUE; -module_param(dhd_pkt_filter_enable, uint, 0); - -/* Pkt filter init setup */ -uint dhd_pkt_filter_init = 0; -module_param(dhd_pkt_filter_init, uint, 0); - -/* Pkt filter mode control */ -#ifdef GAN_LITE_NAT_KEEPALIVE_FILTER -uint dhd_master_mode = FALSE; -#else -uint dhd_master_mode = TRUE; -#endif /* GAL_LITE_NAT_KEEPALIVE_FILTER */ -module_param(dhd_master_mode, uint, 1); - -#ifdef DHDTHREAD -/* Watchdog thread priority, -1 to use kernel timer */ -int dhd_watchdog_prio = 97; -module_param(dhd_watchdog_prio, int, 0); - -/* DPC thread priority, -1 to use tasklet */ -int dhd_dpc_prio = 98; -module_param(dhd_dpc_prio, int, 0); - -/* DPC thread priority, -1 to use tasklet */ -extern int dhd_dongle_memsize; -module_param(dhd_dongle_memsize, int, 0); -#endif /* DHDTHREAD */ -/* Control fw roaming */ -uint dhd_roam_disable = 0; - -/* Control radio state */ -uint dhd_radio_up = 1; - -/* Network inteface name */ -char iface_name[IFNAMSIZ] = {'\0'}; -module_param_string(iface_name, iface_name, IFNAMSIZ, 0); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define DAEMONIZE(a) daemonize(a); \ - allow_signal(SIGKILL); \ - allow_signal(SIGTERM); -#else /* Linux 2.4 (w/o preemption patch) */ -#define RAISE_RX_SOFTIRQ() \ - cpu_raise_softirq(smp_processor_id(), NET_RX_SOFTIRQ) -#define DAEMONIZE(a) daemonize(); \ - do { if (a) \ - strncpy(current->comm, a, MIN(sizeof(current->comm), (strlen(a) + 1))); \ - } while (0); -#endif /* LINUX_VERSION_CODE */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) -#define BLOCKABLE() (!in_atomic()) -#else -#define BLOCKABLE() (!in_interrupt()) -#endif - -/* The following are specific to the SDIO dongle */ - -/* IOCTL response timeout */ -int dhd_ioctl_timeout_msec = IOCTL_RESP_TIMEOUT; - -/* Idle timeout for backplane clock */ -int dhd_idletime = DHD_IDLETIME_TICKS; -module_param(dhd_idletime, int, 0); - -/* Use polling */ -#ifdef CONFIG_MACH_MIDAS_02_BD -uint dhd_poll = TRUE; -#else -uint dhd_poll = FALSE; -#endif -module_param(dhd_poll, uint, 0); - -/* Use interrupts */ -uint dhd_intr = TRUE; -module_param(dhd_intr, uint, 0); - -/* SDIO Drive Strength (in milliamps) */ -uint dhd_sdiod_drive_strength = 6; -module_param(dhd_sdiod_drive_strength, uint, 0); - -/* Tx/Rx bounds */ -extern uint dhd_txbound; -extern uint dhd_rxbound; -module_param(dhd_txbound, uint, 0); -module_param(dhd_rxbound, uint, 0); - -/* Deferred transmits */ -extern uint dhd_deferred_tx; -module_param(dhd_deferred_tx, uint, 0); - -#ifdef BCMDBGFS -extern void dhd_dbg_init(dhd_pub_t *dhdp); -extern void dhd_dbg_remove(void); -#endif /* BCMDBGFS */ - -#ifdef SDTEST -/* Echo packet generator (pkts/s) */ -uint dhd_pktgen = 0; -module_param(dhd_pktgen, uint, 0); - -/* Echo packet len (0 => sawtooth, max 2040) */ -uint dhd_pktgen_len = 0; -module_param(dhd_pktgen_len, uint, 0); -#endif /* SDTEST */ - -/* Version string to report */ -#ifdef DHD_DEBUG -#ifndef SRCBASE -#define SRCBASE "drivers/net/wireless/bcmdhd" -#endif -#define DHD_COMPILED "\nCompiled in " SRCBASE -#else -#define DHD_COMPILED -#endif /* DHD_DEBUG */ - -static char dhd_version[] = "Dongle Host Driver, version " EPI_VERSION_STR -#ifdef DHD_DEBUG -"\nCompiled in " SRCBASE " on " __DATE__ " at " __TIME__ -#endif -; -static void dhd_net_if_lock_local(dhd_info_t *dhd); -static void dhd_net_if_unlock_local(dhd_info_t *dhd); - -#ifdef WLMEDIA_HTSF -void htsf_update(dhd_info_t *dhd, void *data); -tsf_t prev_tsf, cur_tsf; - -uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx); -static int dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx); -static void dhd_dump_latency(void); -static void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf); -static void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf); -static void dhd_dump_htsfhisto(histo_t *his, char *s); -#endif /* WLMEDIA_HTSF */ - -/* Monitor interface */ -int dhd_monitor_init(void *dhd_pub); -int dhd_monitor_uninit(void); - -#ifdef CONFIG_CONTROL_PM -bool g_pm_control; -void sec_control_pm(dhd_pub_t *dhd, uint *); -#endif - -#if defined(CONFIG_WIRELESS_EXT) -struct iw_statistics *dhd_get_wireless_stats(struct net_device *dev); -#endif /* defined(CONFIG_WIRELESS_EXT) */ - -static void dhd_dpc(ulong data); -/* forward decl */ -extern int dhd_wait_pend8021x(struct net_device *dev); - -#ifdef TOE -#ifndef BDC -#error TOE requires BDC -#endif /* !BDC */ -static int dhd_toe_get(dhd_info_t *dhd, int idx, uint32 *toe_ol); -static int dhd_toe_set(dhd_info_t *dhd, int idx, uint32 toe_ol); -#endif /* TOE */ - -static int dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, - wl_event_msg_t *event_ptr, void **data_ptr); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) -static int dhd_sleep_pm_callback(struct notifier_block *nfb, unsigned long action, void *ignored) -{ - int ret = NOTIFY_DONE; -#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 39)) || defined(BCMHOST) - switch (action) { - case PM_HIBERNATION_PREPARE: - case PM_SUSPEND_PREPARE: - dhd_mmc_suspend = TRUE; - ret = NOTIFY_OK; - break; - case PM_POST_HIBERNATION: - case PM_POST_SUSPEND: - dhd_mmc_suspend = FALSE; - ret = NOTIFY_OK; - break; - } - smp_mb(); -#endif - return ret; -} - -static struct notifier_block dhd_sleep_pm_notifier = { - .notifier_call = dhd_sleep_pm_callback, - .priority = 0 -}; -extern int register_pm_notifier(struct notifier_block *nb); -extern int unregister_pm_notifier(struct notifier_block *nb); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - -static void dhd_set_packet_filter(int value, dhd_pub_t *dhd) -{ -#ifdef PKT_FILTER_SUPPORT - DHD_TRACE(("%s: %d\n", __FUNCTION__, value)); - /* 1 - Enable packet filter, only allow unicast packet to send up */ - /* 0 - Disable packet filter */ - if (dhd_pkt_filter_enable && !dhd->dhcp_in_progress) { - int i; -#ifdef PASS_ALL_MCAST_PKTS - char iovbuf[20]; - uint32 allmultivar = !value; -#endif /* PASS_ALL_MCAST_PKTS */ - - for (i = 0; i < dhd->pktfilter_count; i++) { - dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - value, dhd_master_mode); - } -#ifdef PASS_ALL_MCAST_PKTS - bcm_mkiovar("allmulti", (char *)&allmultivar, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* PASS_ALL_MCAST_PKTS */ - } -#endif /* PKT_FILTER_SUPPORT */ -} - -#if defined(CONFIG_HAS_EARLYSUSPEND) -static int dhd_set_suspend(int value, dhd_pub_t *dhd) -{ - char iovbuf[32]; -#ifndef CUSTOMER_HW_SAMSUNG - int power_mode = PM_MAX; - /* wl_pkt_filter_enable_t enable_parm; */ - int bcn_li_dtim = 3; - uint roamvar = 1; -#endif -#ifdef BCM4334_CHIP - int bcn_li_bcn; -#endif -#ifdef PASS_ALL_MCAST_PKTS - uint32 allmulti; -#endif /* PASS_ALL_MCAST_PKTS */ - - DHD_ERROR(("%s: enter, value = %d in_suspend=%d\n", - __FUNCTION__, value, dhd->in_suspend)); - - if (dhd && dhd->up) { - if (value && dhd->in_suspend) { - if (wl_cfgp2p_p2p_listen_suspend()) - DHD_ERROR(("failed to set WLC_E_P2P_PROBREQ_MSG\n")); -#ifdef PKT_FILTER_SUPPORT - dhd->early_suspended = 1; -#endif - - /* Kernel suspended */ - DHD_ERROR(("%s: force extra Suspend setting \n", __FUNCTION__)); - -#ifndef CUSTOMER_HW_SAMSUNG - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); -#endif - - /* Enable packet filter, only allow unicast packet to send up */ - if (dhd_pkt_filter_enable && !dhd->dhcp_in_progress) { - int i; - for (i = 0; i < dhd->pktfilter_count; i++) - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - 1, dhd_master_mode); - } -#ifdef PASS_ALL_MCAST_PKTS - allmulti = 0; - bcm_mkiovar("allmulti", (char *)&allmulti, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* PASS_ALL_MCAST_PKTS */ - -#ifndef CUSTOMER_HW_SAMSUNG - /* If DTIM skip is set up as default, force it to wake - * each third DTIM for better power savings. Note that - * one side effect is a chance to miss BC/MC packet. - */ - bcn_li_dtim = dhd_get_dtim_skip(dhd); - bcm_mkiovar("bcn_li_dtim", (char *)&bcn_li_dtim, - 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - - /* Disable firmware roaming during suspend */ - bcm_mkiovar("roam_off", (char *)&roamvar, 4, - iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif -#ifdef BCM4334_CHIP - bcn_li_bcn = 0; - bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, - 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif - } else { - -#ifdef PKT_FILTER_SUPPORT - dhd->early_suspended = 0; -#endif - - /* Kernel resumed */ - DHD_ERROR(("%s: Remove extra suspend setting \n", __FUNCTION__)); - -#ifndef CUSTOMER_HW_SAMSUNG - power_mode = PM_FAST; - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, - sizeof(power_mode), TRUE, 0); -#endif - - /* disable pkt filter */ - if (dhd_pkt_filter_enable && !dhd->dhcp_in_progress) { - int i; - for (i = 0; i < dhd->pktfilter_count; i++) - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - 0, dhd_master_mode); - } -#ifdef PASS_ALL_MCAST_PKTS - allmulti = 1; - bcm_mkiovar("allmulti", (char *)&allmulti, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* PASS_ALL_MCAST_PKTS */ - -#ifndef CUSTOMER_HW_SAMSUNG - /* restore pre-suspend setting for dtim_skip */ - bcm_mkiovar("bcn_li_dtim", (char *)&dhd->dtim_skip, - 4, iovbuf, sizeof(iovbuf)); - - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - - roamvar = dhd_roam_disable; - bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, - sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif -#ifdef BCM4334_CHIP - bcn_li_bcn = 1; - bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, - 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif - } - } - - return 0; -} - -static void dhd_suspend_resume_helper(struct dhd_info *dhd, int val) -{ - dhd_pub_t *dhdp = &dhd->pub; - - DHD_OS_WAKE_LOCK(dhdp); - /* Set flag when early suspend was called */ - dhdp->in_suspend = val; - if ((!dhdp->suspend_disable_flag) && (dhd_check_ap_wfd_mode_set(dhdp) == FALSE)) - dhd_set_suspend(val, dhdp); - DHD_OS_WAKE_UNLOCK(dhdp); -} - -static void dhd_early_suspend(struct early_suspend *h) -{ - struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); - - DHD_ERROR(("%s: enter\n", __FUNCTION__)); - - if (dhd) - dhd_suspend_resume_helper(dhd, 1); -} - -static void dhd_late_resume(struct early_suspend *h) -{ - struct dhd_info *dhd = container_of(h, struct dhd_info, early_suspend); - - DHD_ERROR(("%s: enter\n", __FUNCTION__)); - - if (dhd) - dhd_suspend_resume_helper(dhd, 0); -} -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ - -/* - * Generalized timeout mechanism. Uses spin sleep with exponential back-off until - * the sleep time reaches one jiffy, then switches over to task delay. Usage: - * - * dhd_timeout_start(&tmo, usec); - * while (!dhd_timeout_expired(&tmo)) - * if (poll_something()) - * break; - * if (dhd_timeout_expired(&tmo)) - * fatal(); - */ - -void -dhd_timeout_start(dhd_timeout_t *tmo, uint usec) -{ - tmo->limit = usec; - tmo->increment = 0; - tmo->elapsed = 0; - tmo->tick = 1000000 / HZ; -} - -int -dhd_timeout_expired(dhd_timeout_t *tmo) -{ - /* Does nothing the first call */ - if (tmo->increment == 0) { - tmo->increment = 1; - return 0; - } - - if (tmo->elapsed >= tmo->limit) - return 1; - - /* Add the delay that's about to take place */ - tmo->elapsed += tmo->increment; - - if (tmo->increment < tmo->tick) { - OSL_DELAY(tmo->increment); - tmo->increment *= 2; - if (tmo->increment > tmo->tick) - tmo->increment = tmo->tick; - } else { - wait_queue_head_t delay_wait; - DECLARE_WAITQUEUE(wait, current); - int pending; - init_waitqueue_head(&delay_wait); - add_wait_queue(&delay_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - pending = signal_pending(current); - remove_wait_queue(&delay_wait, &wait); - set_current_state(TASK_RUNNING); - if (pending) - return 1; /* Interrupted */ - } - - return 0; -} - -int -dhd_net2idx(dhd_info_t *dhd, struct net_device *net) -{ - int i = 0; - - ASSERT(dhd); - while (i < DHD_MAX_IFS) { - if (dhd->iflist[i] && (dhd->iflist[i]->net == net)) - return i; - i++; - } - - return DHD_BAD_IF; -} - -struct net_device * dhd_idx2net(void *pub, int ifidx) -{ - struct dhd_pub *dhd_pub = (struct dhd_pub *)pub; - struct dhd_info *dhd_info; - - if (!dhd_pub || ifidx < 0 || ifidx >= DHD_MAX_IFS) - return NULL; - dhd_info = dhd_pub->info; - if (dhd_info && dhd_info->iflist[ifidx]) - return dhd_info->iflist[ifidx]->net; - return NULL; -} - -int -dhd_ifname2idx(dhd_info_t *dhd, char *name) -{ - int i = DHD_MAX_IFS; - - ASSERT(dhd); - - if (name == NULL || *name == '\0') - return 0; - - while (--i > 0) - if (dhd->iflist[i] && !strncmp(dhd->iflist[i]->name, name, IFNAMSIZ)) - break; - - DHD_TRACE(("%s: return idx %d for \"%s\"\n", __FUNCTION__, i, name)); - - return i; /* default - the primary interface */ -} - -char * -dhd_ifname(dhd_pub_t *dhdp, int ifidx) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - - ASSERT(dhd); - - if (ifidx < 0 || ifidx >= DHD_MAX_IFS) { - DHD_ERROR(("%s: ifidx %d out of range\n", __FUNCTION__, ifidx)); - return "<if_bad>"; - } - - if (dhd->iflist[ifidx] == NULL) { - DHD_ERROR(("%s: null i/f %d\n", __FUNCTION__, ifidx)); - return "<if_null>"; - } - - if (dhd->iflist[ifidx]->net) - return dhd->iflist[ifidx]->net->name; - - return "<if_none>"; -} - -uint8 * -dhd_bssidx2bssid(dhd_pub_t *dhdp, int idx) -{ - int i; - dhd_info_t *dhd = (dhd_info_t *)dhdp; - - ASSERT(dhd); - for (i = 0; i < DHD_MAX_IFS; i++) - if (dhd->iflist[i] && dhd->iflist[i]->bssidx == idx) - return dhd->iflist[i]->mac_addr; - - return NULL; -} - - -static void -_dhd_set_multicast_list(dhd_info_t *dhd, int ifidx) -{ - struct net_device *dev; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - struct netdev_hw_addr *ha; -#else - struct dev_mc_list *mclist; -#endif - uint32 allmulti, cnt; - - wl_ioctl_t ioc; - char *buf, *bufp; - uint buflen; - int ret; - -#ifdef MCAST_LIST_ACCUMULATION - int i; - uint32 cnt_iface[DHD_MAX_IFS]; - cnt = 0; - allmulti = 0; - - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - dev = dhd->iflist[i]->net; -#else - ASSERT(dhd && dhd->iflist[ifidx]); - dev = dhd->iflist[ifidx]->net; -#endif /* MCAST_LIST_ACCUMULATION */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_lock_bh(dev); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) -#ifdef MCAST_LIST_ACCUMULATION - cnt_iface[i] = netdev_mc_count(dev); - cnt += cnt_iface[i]; -#else - cnt = netdev_mc_count(dev); -#endif /* MCAST_LIST_ACCUMULATION */ -#else -#ifdef MCAST_LIST_ACCUMULATION - cnt += dev->mc_count; -#else - cnt = dev->mc_count; -#endif /* MCAST_LIST_ACCUMULATION */ -#endif /* LINUX_VERSION_CODE */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_unlock_bh(dev); -#endif - - /* Determine initial value of allmulti flag */ -#ifdef MCAST_LIST_ACCUMULATION - allmulti |= (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; - } - } -#else - allmulti = (dev->flags & IFF_ALLMULTI) ? TRUE : FALSE; -#endif /* MCAST_LIST_ACCUMULATION */ - -#ifdef PASS_ALL_MCAST_PKTS -#ifdef PKT_FILTER_SUPPORT - if (!dhd->pub.early_suspended) - allmulti = TRUE; -#endif -#endif /* PASS_ALL_MCAST_PKTS */ - - /* Send down the multicast list first. */ - - - buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETHER_ADDR_LEN); - if (!(bufp = buf = MALLOC(dhd->pub.osh, buflen))) { - DHD_ERROR(("%s: out of memory for mcast_list, cnt %d\n", - dhd_ifname(&dhd->pub, ifidx), cnt)); - return; - } - - strcpy(bufp, "mcast_list"); - bufp += strlen("mcast_list") + 1; - - cnt = htol32(cnt); - memcpy(bufp, &cnt, sizeof(cnt)); - bufp += sizeof(cnt); - -#ifdef MCAST_LIST_ACCUMULATION - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - DHD_TRACE(("_dhd_set_multicast_list: ifidx %d\n", i)); /* Shinuk */ - dev = dhd->iflist[i]->net; -#endif /* MCAST_LIST_ACCUMULATION */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_lock_bh(dev); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 35) - netdev_for_each_mc_addr(ha, dev) { -#ifdef MCAST_LIST_ACCUMULATION - if (!cnt_iface[i]) -#else - if (!cnt) -#endif /* MCAST_LIST_ACCUMULATION */ - break; - memcpy(bufp, ha->addr, ETHER_ADDR_LEN); - bufp += ETHER_ADDR_LEN; -#ifdef MCAST_LIST_ACCUMULATION - DHD_TRACE(("_dhd_set_multicast_list: cnt %d %02x:%02x:%02x:%02x:%02x:%02x\n", - cnt_iface[i], ha->addr[0], ha->addr[1], - ha->addr[2], ha->addr[3], ha->addr[4], - ha->addr[5])); /* Shinuk */ - cnt_iface[i]--; -#else - cnt--; -#endif /* MCAST_LIST_ACCUMULATION */ - - } -#else -#ifdef MCAST_LIST_ACCUMULATION - for (mclist = dev->mc_list; (mclist && (cnt_iface[i] > 0)); cnt_iface[i]--, mclist = mclist->next) { -#else - for (mclist = dev->mc_list; (mclist && (cnt > 0)); cnt--, mclist = mclist->next) { -#endif /* MCAST_LIST_ACCUMULATION */ - memcpy(bufp, (void *)mclist->dmi_addr, ETHER_ADDR_LEN); - bufp += ETHER_ADDR_LEN; - } -#endif /* LINUX_VERSION_CODE */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) - netif_addr_unlock_bh(dev); -#endif - -#ifdef MCAST_LIST_ACCUMULATION - } - } -#endif /* MCAST_LIST_ACCUMULATION */ - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = buflen; - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); - if (ret < 0) { - DHD_ERROR(("%s: set mcast_list failed, cnt %d\n", - dhd_ifname(&dhd->pub, ifidx), cnt)); - allmulti = cnt ? TRUE : allmulti; - } - - MFREE(dhd->pub.osh, buf, buflen); - - /* Now send the allmulti setting. This is based on the setting in the - * net_device flags, but might be modified above to be turned on if we - * were trying to set some addresses and dongle rejected it... - */ - - buflen = sizeof("allmulti") + sizeof(allmulti); - if (!(buf = MALLOC(dhd->pub.osh, buflen))) { - DHD_ERROR(("%s: out of memory for allmulti\n", dhd_ifname(&dhd->pub, ifidx))); - return; - } - allmulti = htol32(allmulti); - - if (!bcm_mkiovar("allmulti", (void*)&allmulti, sizeof(allmulti), buf, buflen)) { - DHD_ERROR(("%s: mkiovar failed for allmulti, datalen %d buflen %u\n", - dhd_ifname(&dhd->pub, ifidx), (int)sizeof(allmulti), buflen)); - MFREE(dhd->pub.osh, buf, buflen); - return; - } - - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = buflen; - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); - if (ret < 0) { - DHD_ERROR(("%s: set allmulti %d failed\n", - dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); - } - - MFREE(dhd->pub.osh, buf, buflen); - - /* Finally, pick up the PROMISC flag as well, like the NIC driver does */ - -#ifdef MCAST_LIST_ACCUMULATION - allmulti = 0; - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - dev = dhd->iflist[i]->net; - allmulti |= (dev->flags & IFF_PROMISC) ? TRUE : FALSE; - } - } -#else - allmulti = (dev->flags & IFF_PROMISC) ? TRUE : FALSE; -#endif /* MCAST_LIST_ACCUMULATION */ - - allmulti = htol32(allmulti); - - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_PROMISC; - ioc.buf = &allmulti; - ioc.len = sizeof(allmulti); - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); - if (ret < 0) { - DHD_ERROR(("%s: set promisc %d failed\n", - dhd_ifname(&dhd->pub, ifidx), ltoh32(allmulti))); - } -} - -#ifdef CUSTOMER_HW_SAMSUNG -int -#else -static int -#endif -_dhd_set_mac_address(dhd_info_t *dhd, int ifidx, struct ether_addr *addr) -{ - char buf[32]; - wl_ioctl_t ioc; - int ret; - - if (!bcm_mkiovar("cur_etheraddr", (char*)addr, ETHER_ADDR_LEN, buf, 32)) { - DHD_ERROR(("%s: mkiovar failed for cur_etheraddr\n", dhd_ifname(&dhd->pub, ifidx))); - return -1; - } - memset(&ioc, 0, sizeof(ioc)); - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = 32; - ioc.set = TRUE; - - ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len); - if (ret < 0) { - DHD_ERROR(("%s: set cur_etheraddr failed\n", dhd_ifname(&dhd->pub, ifidx))); - } else { - memcpy(dhd->iflist[ifidx]->net->dev_addr, addr, ETHER_ADDR_LEN); - memcpy(dhd->pub.mac.octet, addr, ETHER_ADDR_LEN); - } - - return ret; -} - -#ifdef SOFTAP -extern struct net_device *ap_net_dev; -extern tsk_ctl_t ap_eth_ctl; /* ap netdev heper thread ctl */ -#endif - -static void -dhd_op_if(dhd_if_t *ifp) -{ - dhd_info_t *dhd; - int ret = 0, err = 0; -#ifdef SOFTAP - unsigned long flags; -#endif - - if (!ifp || !ifp->info || !ifp->idx) - return; - ASSERT(ifp && ifp->info && ifp->idx); /* Virtual interfaces only */ - dhd = ifp->info; - - DHD_TRACE(("%s: idx %d, state %d\n", __FUNCTION__, ifp->idx, ifp->state)); - -#ifdef WL_CFG80211 - if (wl_cfg80211_is_progress_ifchange()) - return; - -#endif - switch (ifp->state) { - case DHD_IF_ADD: - /* - * Delete the existing interface before overwriting it - * in case we missed the WLC_E_IF_DEL event. - */ - if (ifp->net != NULL) { - DHD_ERROR(("%s: ERROR: netdev:%s already exists, try free & unregister \n", - __FUNCTION__, ifp->net->name)); - netif_stop_queue(ifp->net); - unregister_netdev(ifp->net); - free_netdev(ifp->net); - } - /* Allocate etherdev, including space for private structure */ - if (!(ifp->net = alloc_etherdev(sizeof(dhd)))) { - DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); - ret = -ENOMEM; - } - if (ret == 0) { - strncpy(ifp->net->name, ifp->name, IFNAMSIZ); - ifp->net->name[IFNAMSIZ - 1] = '\0'; - memcpy(netdev_priv(ifp->net), &dhd, sizeof(dhd)); -#ifdef WL_CFG80211 - if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) - if (!wl_cfg80211_notify_ifadd(ifp->net, ifp->idx, ifp->bssidx, - (void*)dhd_net_attach)) { - ifp->state = DHD_IF_NONE; - ifp->event2cfg80211 = TRUE; - return; - } -#endif - if ((err = dhd_net_attach(&dhd->pub, ifp->idx)) != 0) { - DHD_ERROR(("%s: dhd_net_attach failed, err %d\n", - __FUNCTION__, err)); - ret = -EOPNOTSUPP; - } else { -#if defined(SOFTAP) - if (ap_fw_loaded && !(dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { - /* semaphore that the soft AP CODE waits on */ - flags = dhd_os_spin_lock(&dhd->pub); - - /* save ptr to wl0.1 netdev for use in wl_iw.c */ - ap_net_dev = ifp->net; - /* signal to the SOFTAP 'sleeper' thread, wl0.1 is ready */ - up(&ap_eth_ctl.sema); - dhd_os_spin_unlock(&dhd->pub, flags); - } -#endif - DHD_TRACE(("\n ==== pid:%x, net_device for if:%s created ===\n\n", - current->pid, ifp->net->name)); - ifp->state = DHD_IF_NONE; - } - } - break; - case DHD_IF_DEL: - /* Make sure that we don't enter again here if .. */ - /* dhd_op_if is called again from some other context */ - ifp->state = DHD_IF_DELETING; - if (ifp->net != NULL) { - DHD_ERROR(("\n%s: (WAR TRACE) got 'DHD_IF_DEL' state\n", __FUNCTION__)); - netif_stop_queue(ifp->net); -#ifdef WL_CFG80211 - if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { - wl_cfg80211_notify_ifdel(ifp->net); - } -#endif - unregister_netdev(ifp->net); - ret = DHD_DEL_IF; /* Make sure the free_netdev() is called */ - } - break; - case DHD_IF_DELETING: - break; - default: - DHD_ERROR(("%s: bad op %d\n", __FUNCTION__, ifp->state)); - ASSERT(!ifp->state); - break; - } - - if (ret < 0) { - ifp->set_multicast = FALSE; - if (ifp->net) { - free_netdev(ifp->net); - ifp->net = NULL; - } - dhd->iflist[ifp->idx] = NULL; -#ifdef SOFTAP - flags = dhd_os_spin_lock(&dhd->pub); - if (ifp->net == ap_net_dev) - ap_net_dev = NULL; /* NULL SOFTAP global wl0.1 as well */ - dhd_os_spin_unlock(&dhd->pub, flags); -#endif /* SOFTAP */ - MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); - } -} - -static int -_dhd_sysioc_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - - - int i; -#ifdef SOFTAP - bool in_ap = FALSE; - unsigned long flags; -#endif - - DAEMONIZE("dhd_sysioc"); - - complete(&tsk->completed); - - while (down_interruptible(&tsk->sema) == 0) { -#ifdef MCAST_LIST_ACCUMULATION - bool set_multicast = FALSE; -#endif /* MCAST_LIST_ACCUMULATION */ - - SMP_RD_BARRIER_DEPENDS(); - if (tsk->terminated) { - break; - } - - dhd_net_if_lock_local(dhd); - DHD_OS_WAKE_LOCK(&dhd->pub); - - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - DHD_TRACE(("%s: interface %d\n", __FUNCTION__, i)); -#ifdef SOFTAP - flags = dhd_os_spin_lock(&dhd->pub); - in_ap = (ap_net_dev != NULL); - dhd_os_spin_unlock(&dhd->pub, flags); -#endif /* SOFTAP */ - if (dhd->iflist[i] && dhd->iflist[i]->state) - dhd_op_if(dhd->iflist[i]); - - if (dhd->iflist[i] == NULL) { - DHD_TRACE(("\n\n %s: interface %d just been removed," - "!\n\n", __FUNCTION__, i)); - continue; - } -#ifdef SOFTAP - if (in_ap && dhd->set_macaddress == i+1) { - DHD_TRACE(("attempt to set MAC for %s in AP Mode," - "blocked. \n", dhd->iflist[i]->net->name)); - dhd->set_macaddress = 0; - continue; - } - - if (in_ap && dhd->iflist[i]->set_multicast) { - DHD_TRACE(("attempt to set MULTICAST list for %s" - "in AP Mode, blocked. \n", dhd->iflist[i]->net->name)); - dhd->iflist[i]->set_multicast = FALSE; - continue; - } -#endif /* SOFTAP */ - if (dhd->pub.up == 0) - continue; - if (dhd->iflist[i]->set_multicast) { - dhd->iflist[i]->set_multicast = FALSE; -#ifdef MCAST_LIST_ACCUMULATION - set_multicast = TRUE; -#else - _dhd_set_multicast_list(dhd, i); -#endif /* MCAST_LIST_ACCUMULATION */ - - } - if (dhd->set_macaddress == i+1) { - dhd->set_macaddress = 0; - if (0 == _dhd_set_mac_address(dhd, i, &dhd->macvalue)) - DHD_INFO(("dhd_sysioc_thread: MACID is overwritten\n")); - else - DHD_ERROR(("dhd_sysioc_thread: _dhd_set_mac_address() failed\n")); - } - } - } -#ifdef MCAST_LIST_ACCUMULATION - if (set_multicast) - _dhd_set_multicast_list(dhd, 0); -#endif /* MCAST_LIST_ACCUMULATION */ - - DHD_OS_WAKE_UNLOCK(&dhd->pub); - dhd_net_if_unlock_local(dhd); - } - DHD_TRACE(("%s: stopped\n", __FUNCTION__)); - complete_and_exit(&tsk->completed, 0); -} - -static int -dhd_set_mac_address(struct net_device *dev, void *addr) -{ - int ret = 0; - - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - struct sockaddr *sa = (struct sockaddr *)addr; - int ifidx; - - ifidx = dhd_net2idx(dhd, dev); - if (ifidx == DHD_BAD_IF) - return -1; - - ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); - memcpy(&dhd->macvalue, sa->sa_data, ETHER_ADDR_LEN); - dhd->set_macaddress = ifidx+1; - up(&dhd->thr_sysioc_ctl.sema); - - return ret; -} - -static void -dhd_set_multicast_list(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ifidx; - - ifidx = dhd_net2idx(dhd, dev); - if (ifidx == DHD_BAD_IF) - return; - - ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); - dhd->iflist[ifidx]->set_multicast = TRUE; - up(&dhd->thr_sysioc_ctl.sema); -} - -#ifdef PROP_TXSTATUS -int -dhd_os_wlfc_block(dhd_pub_t *pub) -{ - dhd_info_t *di = (dhd_info_t *)(pub->info); - ASSERT(di != NULL); - spin_lock_bh(&di->wlfc_spinlock); - return 1; -} - -int -dhd_os_wlfc_unblock(dhd_pub_t *pub) -{ - dhd_info_t *di = (dhd_info_t *)(pub->info); - - (void)di; - ASSERT(di != NULL); - spin_unlock_bh(&di->wlfc_spinlock); - return 1; -} - -const uint8 wme_fifo2ac[] = { 0, 1, 2, 3, 1, 1 }; -uint8 prio2fifo[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; -#define WME_PRIO2AC(prio) wme_fifo2ac[prio2fifo[(prio)]] - -#endif /* PROP_TXSTATUS */ -int -dhd_sendpkt(dhd_pub_t *dhdp, int ifidx, void *pktbuf) -{ - int ret; - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct ether_header *eh = NULL; - - /* Reject if down */ - if (!dhdp->up || (dhdp->busstate == DHD_BUS_DOWN)) { - /* free the packet here since the caller won't */ - PKTFREE(dhdp->osh, pktbuf, TRUE); - return -ENODEV; - } - - /* Update multicast statistic */ - if (PKTLEN(dhdp->osh, pktbuf) >= ETHER_HDR_LEN) { - uint8 *pktdata = (uint8 *)PKTDATA(dhdp->osh, pktbuf); - eh = (struct ether_header *)pktdata; - - if (ETHER_ISMULTI(eh->ether_dhost)) - dhdp->tx_multicast++; - if (ntoh16(eh->ether_type) == ETHER_TYPE_802_1X) - atomic_inc(&dhd->pend_8021x_cnt); - } else { - PKTFREE(dhd->pub.osh, pktbuf, TRUE); - return BCME_ERROR; - } - - /* Look into the packet and update the packet priority */ - if (PKTPRIO(pktbuf) == 0) - pktsetprio(pktbuf, FALSE); - -#ifdef PROP_TXSTATUS - if (dhdp->wlfc_state) { - /* store the interface ID */ - DHD_PKTTAG_SETIF(PKTTAG(pktbuf), ifidx); - - /* store destination MAC in the tag as well */ - DHD_PKTTAG_SETDSTN(PKTTAG(pktbuf), eh->ether_dhost); - - /* decide which FIFO this packet belongs to */ - if (ETHER_ISMULTI(eh->ether_dhost)) - /* one additional queue index (highest AC + 1) is used for bc/mc queue */ - DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), AC_COUNT); - else - DHD_PKTTAG_SETFIFO(PKTTAG(pktbuf), WME_PRIO2AC(PKTPRIO(pktbuf))); - } else -#endif /* PROP_TXSTATUS */ - /* If the protocol uses a data header, apply it */ - dhd_prot_hdrpush(dhdp, ifidx, pktbuf); - - /* Use bus module to send data frame */ -#ifdef WLMEDIA_HTSF - dhd_htsf_addtxts(dhdp, pktbuf); -#endif -#ifdef PROP_TXSTATUS - if (dhdp->wlfc_state && ((athost_wl_status_info_t*)dhdp->wlfc_state)->proptxstatus_mode - != WLFC_FCMODE_NONE) { - dhd_os_wlfc_block(dhdp); - ret = dhd_wlfc_enque_sendq(dhdp->wlfc_state, DHD_PKTTAG_FIFO(PKTTAG(pktbuf)), - pktbuf); - dhd_wlfc_commit_packets(dhdp->wlfc_state, (f_commitpkt_t)dhd_bus_txdata, - dhdp->bus); - if (((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if) { - ((athost_wl_status_info_t*)dhdp->wlfc_state)->toggle_host_if = 0; - } - dhd_os_wlfc_unblock(dhdp); - } - else - /* non-proptxstatus way */ - ret = dhd_bus_txdata(dhdp->bus, pktbuf); -#else - ret = dhd_bus_txdata(dhdp->bus, pktbuf); -#endif /* PROP_TXSTATUS */ - - return ret; -} - -int -dhd_start_xmit(struct sk_buff *skb, struct net_device *net) -{ - int ret; - void *pktbuf; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - int ifidx; -#ifdef WLMEDIA_HTSF - uint8 htsfdlystat_sz = dhd->pub.htsfdlystat_sz; -#else - uint8 htsfdlystat_sz = 0; -#endif - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - DHD_OS_WAKE_LOCK(&dhd->pub); - - /* Reject if down */ -#ifdef CUSTOMER_HW_SAMSUNG - /* - * CSP #506108 - * kernel panic issue when first bootup time, - * rmmod without interface down make unnecessary hang event. - */ - if (dhd->pub.busstate == DHD_BUS_DOWN || dhd->pub.hang_was_sent) { - DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", - __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); - netif_stop_queue(net); - /* Send Event when bus down detected during data session */ - if (dhd->pub.up) { - DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); - net_os_send_hang_message(net); - } - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return -ENODEV; - } -#else - if (!dhd->pub.up || (dhd->pub.busstate == DHD_BUS_DOWN)) { - DHD_ERROR(("%s: xmit rejected pub.up=%d busstate=%d \n", - __FUNCTION__, dhd->pub.up, dhd->pub.busstate)); - netif_stop_queue(net); - /* Send Event when bus down detected during data session */ - if (dhd->pub.busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: Event HANG sent up\n", __FUNCTION__)); - net_os_send_hang_message(net); - } - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return -ENODEV; - } -#endif /* CUSTOMER_HW_SAMSUNG */ - - ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: bad ifidx %d\n", __FUNCTION__, ifidx)); - netif_stop_queue(net); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return -ENODEV; - } - - /* Make sure there's enough room for any header */ - - if (skb_headroom(skb) < dhd->pub.hdrlen + htsfdlystat_sz) { - struct sk_buff *skb2; - - DHD_INFO(("%s: insufficient headroom\n", - dhd_ifname(&dhd->pub, ifidx))); - dhd->pub.tx_realloc++; - - skb2 = skb_realloc_headroom(skb, dhd->pub.hdrlen + htsfdlystat_sz); - - dev_kfree_skb(skb); - if ((skb = skb2) == NULL) { - DHD_ERROR(("%s: skb_realloc_headroom failed\n", - dhd_ifname(&dhd->pub, ifidx))); - ret = -ENOMEM; - goto done; - } - } - - /* Convert to packet */ - if (!(pktbuf = PKTFRMNATIVE(dhd->pub.osh, skb))) { - DHD_ERROR(("%s: PKTFRMNATIVE failed\n", - dhd_ifname(&dhd->pub, ifidx))); - dev_kfree_skb_any(skb); - ret = -ENOMEM; - goto done; - } -#ifdef WLMEDIA_HTSF - if (htsfdlystat_sz && PKTLEN(dhd->pub.osh, pktbuf) >= ETHER_ADDR_LEN) { - uint8 *pktdata = (uint8 *)PKTDATA(dhd->pub.osh, pktbuf); - struct ether_header *eh = (struct ether_header *)pktdata; - - if (!ETHER_ISMULTI(eh->ether_dhost) && - (ntoh16(eh->ether_type) == ETHER_TYPE_IP)) { - eh->ether_type = hton16(ETHER_TYPE_BRCM_PKTDLYSTATS); - } - } -#endif - - ret = dhd_sendpkt(&dhd->pub, ifidx, pktbuf); - - -done: - if (ret) - dhd->pub.dstats.tx_dropped++; - else - dhd->pub.tx_packets++; - - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - /* Return ok: we always eat the packet */ - return 0; -} - -void -dhd_txflowcontrol(dhd_pub_t *dhdp, int ifidx, bool state) -{ - struct net_device *net; - dhd_info_t *dhd = dhdp->info; - int i; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - dhdp->txoff = state; - ASSERT(dhd); - - if (ifidx == ALL_INTERFACES) { - /* Flow control on all active interfaces */ - for (i = 0; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - net = dhd->iflist[i]->net; - if (state == ON) - netif_stop_queue(net); - else - netif_wake_queue(net); - } - } - } - else { - if (dhd->iflist[ifidx]) { - net = dhd->iflist[ifidx]->net; - if (state == ON) - netif_stop_queue(net); - else - netif_wake_queue(net); - } - } -} - -#ifdef DHD_RX_DUMP -typedef struct { - uint16 type; - const char *str; -} PKTTYPE_INFO; - -static const PKTTYPE_INFO packet_type_info[] = -{ - { ETHER_TYPE_IP, "IP" }, - { ETHER_TYPE_ARP, "ARP" }, - { ETHER_TYPE_BRCM, "BRCM" }, - { ETHER_TYPE_802_1X, "802.1X" }, - { ETHER_TYPE_WAI, "WAPI" }, - { 0, ""} -}; - -static const char *_get_packet_type_str(uint16 type) -{ - int i; - int n = sizeof(packet_type_info)/sizeof(packet_type_info[1]) - 1; - for (i = 0; i < n; i++) { - if (packet_type_info[i].type == type) - return packet_type_info[i].str; - } - - return packet_type_info[n].str; -} -#endif /* DHD_RX_DUMP */ - -void -dhd_rx_frame(dhd_pub_t *dhdp, int ifidx, void *pktbuf, int numpkt, uint8 chan) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - struct sk_buff *skb; - uchar *eth; - uint len; - void *data, *pnext = NULL; - int i; - dhd_if_t *ifp; - wl_event_msg_t event; - int tout = DHD_PACKET_TIMEOUT_MS; -#ifdef DHD_RX_DUMP -#ifdef DHD_RX_FULL_DUMP - int k; -#endif /* DHD_RX_FULL_DUMP */ - char *dump_data; - uint16 protocol; -#endif /* DHD_RX_DUMP */ - - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - for (i = 0; pktbuf && i < numpkt; i++, pktbuf = pnext) { -#ifdef WLBTAMP - struct ether_header *eh; - struct dot11_llc_snap_header *lsh; -#endif - - ifp = dhd->iflist[ifidx]; - if (ifp == NULL) { - DHD_ERROR(("%s: ifp is NULL. drop packet\n", - __FUNCTION__)); - PKTFREE(dhdp->osh, pktbuf, TRUE); - continue; - } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - /* Dropping packets before registering net device to avoid kernel panic */ - if (!ifp->net || ifp->net->reg_state != NETREG_REGISTERED || - !dhd->pub.up) { - DHD_ERROR(("%s: net device is NOT registered yet. drop packet\n", - __FUNCTION__)); - PKTFREE(dhdp->osh, pktbuf, TRUE); - continue; - } -#endif - - pnext = PKTNEXT(dhdp->osh, pktbuf); - PKTSETNEXT(wl->sh.osh, pktbuf, NULL); - -#ifdef WLBTAMP - eh = (struct ether_header *)PKTDATA(wl->sh.osh, pktbuf); - lsh = (struct dot11_llc_snap_header *)&eh[1]; - - if ((ntoh16(eh->ether_type) < ETHER_TYPE_MIN) && - (PKTLEN(wl->sh.osh, pktbuf) >= RFC1042_HDR_LEN) && - bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && - lsh->type == HTON16(BTA_PROT_L2CAP)) { - amp_hci_ACL_data_t *ACL_data = (amp_hci_ACL_data_t *) - ((uint8 *)eh + RFC1042_HDR_LEN); - ACL_data = NULL; - } -#endif /* WLBTAMP */ - -#ifdef PROP_TXSTATUS - if (dhdp->wlfc_state && PKTLEN(wl->sh.osh, pktbuf) == 0) { - /* WLFC may send header only packet when - there is an urgent message but no packet to - piggy-back on - */ - ((athost_wl_status_info_t*)dhdp->wlfc_state)->stats.wlfc_header_only_pkt++; - PKTFREE(dhdp->osh, pktbuf, TRUE); - continue; - } -#endif - - skb = PKTTONATIVE(dhdp->osh, pktbuf); - - /* Get the protocol, maintain skb around eth_type_trans() - * The main reason for this hack is for the limitation of - * Linux 2.4 where 'eth_type_trans' uses the 'net->hard_header_len' - * to perform skb_pull inside vs ETH_HLEN. Since to avoid - * coping of the packet coming from the network stack to add - * BDC, Hardware header etc, during network interface registration - * we set the 'net->hard_header_len' to ETH_HLEN + extra space required - * for BDC, Hardware header etc. and not just the ETH_HLEN - */ - eth = skb->data; - len = skb->len; - -#ifdef DHD_RX_DUMP - dump_data = skb->data; - protocol = (dump_data[12] << 8) | dump_data[13]; - DHD_ERROR(("RX DUMP - %s\n", _get_packet_type_str(protocol))); -#ifdef DHD_RX_FULL_DUMP - if (protocol != ETHER_TYPE_BRCM) { - for (k = 0; k < skb->len; k++) { - DHD_ERROR(("%02X ", dump_data[k])); - if ((k & 15) == 15) - DHD_ERROR(("\n")); - } - DHD_ERROR(("\n")); - } -#endif /* DHD_RX_FULL_DUMP */ - if (protocol != ETHER_TYPE_BRCM) { - if (dump_data[0] == 0xFF) { - DHD_ERROR(("%s: BROADCAST\n", __FUNCTION__)); - - if ((dump_data[12] == 8) && - (dump_data[13] == 6)) { - DHD_ERROR(("%s: ARP %d\n", - __FUNCTION__, dump_data[0x15])); - } - } else if (dump_data[0] & 1) { - DHD_ERROR(("%s: MULTICAST: " - "%02X:%02X:%02X:%02X:%02X:%02X\n", - __FUNCTION__, dump_data[0], - dump_data[1], dump_data[2], - dump_data[3], dump_data[4], - dump_data[5])); - } - - if (protocol == ETHER_TYPE_802_1X) { - DHD_ERROR(("ETHER_TYPE_802_1X: " - "ver %d, type %d, replay %d\n", - dump_data[14], dump_data[15], - dump_data[30])); - } - } - -#endif /* DHD_RX_DUMP */ - - ifp = dhd->iflist[ifidx]; - if (ifp == NULL) - ifp = dhd->iflist[0]; - - ASSERT(ifp); - skb->dev = ifp->net; - skb->protocol = eth_type_trans(skb, skb->dev); - - if (skb->pkt_type == PACKET_MULTICAST) { - dhd->pub.rx_multicast++; - } - - skb->data = eth; - skb->len = len; - -#ifdef WLMEDIA_HTSF - dhd_htsf_addrxts(dhdp, pktbuf); -#endif - /* Strip header, count, deliver upward */ - skb_pull(skb, ETH_HLEN); - - /* Process special event packets and then discard them */ - if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) { - dhd_wl_host_event(dhd, &ifidx, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22) - skb->mac_header, -#else - skb->mac.raw, -#endif - &event, - &data); - -#ifdef WLBTAMP - wl_event_to_host_order(&event); - if (event.event_type == WLC_E_BTA_HCI_EVENT) { - dhd_bta_doevt(dhdp, data, event.datalen); - } - tout = DHD_EVENT_TIMEOUT_MS; -#endif /* WLBTAMP */ - } - - ASSERT(ifidx < DHD_MAX_IFS && dhd->iflist[ifidx]); - if (dhd->iflist[ifidx] && !dhd->iflist[ifidx]->state) - ifp = dhd->iflist[ifidx]; - - if (ifp->net) - ifp->net->last_rx = jiffies; - - dhdp->dstats.rx_bytes += skb->len; - dhdp->rx_packets++; /* Local count */ - - if (in_interrupt()) { - netif_rx(skb); - } else { - /* If the receive is not processed inside an ISR, - * the softirqd must be woken explicitly to service - * the NET_RX_SOFTIRQ. In 2.6 kernels, this is handled - * by netif_rx_ni(), but in earlier kernels, we need - * to do it manually. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) - netif_rx_ni(skb); -#else - ulong flags; - netif_rx(skb); - local_irq_save(flags); - RAISE_RX_SOFTIRQ(); - local_irq_restore(flags); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) */ - } - } - DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(dhdp, tout); -} - -void -dhd_event(struct dhd_info *dhd, char *evpkt, int evlen, int ifidx) -{ - /* Linux version has nothing to do */ - return; -} - -void -dhd_txcomplete(dhd_pub_t *dhdp, void *txp, bool success) -{ - uint ifidx; - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct ether_header *eh; - uint16 type; -#ifdef WLBTAMP - uint len; -#endif - - dhd_prot_hdrpull(dhdp, &ifidx, txp, NULL, NULL); - - eh = (struct ether_header *)PKTDATA(dhdp->osh, txp); - type = ntoh16(eh->ether_type); - - if (type == ETHER_TYPE_802_1X) - atomic_dec(&dhd->pend_8021x_cnt); - -#ifdef WLBTAMP - /* Crack open the packet and check to see if it is BT HCI ACL data packet. - * If yes generate packet completion event. - */ - len = PKTLEN(dhdp->osh, txp); - - /* Generate ACL data tx completion event locally to avoid SDIO bus transaction */ - if ((type < ETHER_TYPE_MIN) && (len >= RFC1042_HDR_LEN)) { - struct dot11_llc_snap_header *lsh = (struct dot11_llc_snap_header *)&eh[1]; - - if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) == 0 && - ntoh16(lsh->type) == BTA_PROT_L2CAP) { - - dhd_bta_tx_hcidata_complete(dhdp, txp, success); - } - } -#endif /* WLBTAMP */ -} - -static struct net_device_stats * -dhd_get_stats(struct net_device *net) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - dhd_if_t *ifp; - int ifidx; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: BAD_IF\n", __FUNCTION__)); - return NULL; - } - - ifp = dhd->iflist[ifidx]; - ASSERT(dhd && ifp); - - if (dhd->pub.up) { - /* Use the protocol to get dongle stats */ - dhd_prot_dstats(&dhd->pub); - } - - /* Copy dongle stats to net device stats */ - ifp->stats.rx_packets = dhd->pub.dstats.rx_packets; - ifp->stats.tx_packets = dhd->pub.dstats.tx_packets; - ifp->stats.rx_bytes = dhd->pub.dstats.rx_bytes; - ifp->stats.tx_bytes = dhd->pub.dstats.tx_bytes; - ifp->stats.rx_errors = dhd->pub.dstats.rx_errors; - ifp->stats.tx_errors = dhd->pub.dstats.tx_errors; - ifp->stats.rx_dropped = dhd->pub.dstats.rx_dropped; - ifp->stats.tx_dropped = dhd->pub.dstats.tx_dropped; - ifp->stats.multicast = dhd->pub.dstats.multicast; - - return &ifp->stats; -} - -#ifdef DHDTHREAD -static int -dhd_watchdog_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - /* This thread doesn't need any user-level access, - * so get rid of all our resources - */ - if (dhd_watchdog_prio > 0) { - struct sched_param param; - param.sched_priority = (dhd_watchdog_prio < MAX_RT_PRIO)? - dhd_watchdog_prio:(MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - - DAEMONIZE("dhd_watchdog"); - - /* Run until signal received */ - complete(&tsk->completed); - - while (1) - if (down_interruptible (&tsk->sema) == 0) { - unsigned long flags; - - SMP_RD_BARRIER_DEPENDS(); - if (tsk->terminated) { - break; - } - - dhd_os_sdlock(&dhd->pub); - if (dhd->pub.dongle_reset == FALSE) { - DHD_TIMER(("%s:\n", __FUNCTION__)); - - /* Call the bus module watchdog */ - dhd_bus_watchdog(&dhd->pub); - - flags = dhd_os_spin_lock(&dhd->pub); - /* Count the tick for reference */ - dhd->pub.tickcnt++; - /* Reschedule the watchdog */ - if (dhd->wd_timer_valid) - mod_timer(&dhd->timer, - jiffies + dhd_watchdog_ms * HZ / 1000); - dhd_os_spin_unlock(&dhd->pub, flags); - } - dhd_os_sdunlock(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } else { - break; - } - - complete_and_exit(&tsk->completed, 0); -} -#endif /* DHDTHREAD */ - -static void dhd_watchdog(ulong data) -{ - dhd_info_t *dhd = (dhd_info_t *)data; - unsigned long flags; - - /* To avoid kernel panic */ - if (!dhd->wd_timer_valid) - return; - - DHD_OS_WAKE_LOCK(&dhd->pub); - if (dhd->pub.dongle_reset) { - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return; - } - -#ifdef DHDTHREAD - if (dhd->thr_wdt_ctl.thr_pid >= 0) { - up(&dhd->thr_wdt_ctl.sema); - return; - } -#endif /* DHDTHREAD */ - - dhd_os_sdlock(&dhd->pub); - /* Call the bus module watchdog */ - dhd_bus_watchdog(&dhd->pub); - - flags = dhd_os_spin_lock(&dhd->pub); - /* Count the tick for reference */ - dhd->pub.tickcnt++; - - /* Reschedule the watchdog */ - if (dhd->wd_timer_valid) - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); - dhd_os_spin_unlock(&dhd->pub, flags); - dhd_os_sdunlock(&dhd->pub); - DHD_OS_WAKE_UNLOCK(&dhd->pub); -} - -#ifdef DHDTHREAD -static int -dhd_dpc_thread(void *data) -{ - tsk_ctl_t *tsk = (tsk_ctl_t *)data; - dhd_info_t *dhd = (dhd_info_t *)tsk->parent; - - /* This thread doesn't need any user-level access, - * so get rid of all our resources - */ - if (dhd_dpc_prio > 0) - { - struct sched_param param; - param.sched_priority = (dhd_dpc_prio < MAX_RT_PRIO)?dhd_dpc_prio:(MAX_RT_PRIO-1); - setScheduler(current, SCHED_FIFO, ¶m); - } - - DAEMONIZE("dhd_dpc"); - /* DHD_OS_WAKE_LOCK is called in dhd_sched_dpc[dhd_linux.c] down below */ - - /* signal: thread has started */ - complete(&tsk->completed); - - /* Run until signal received */ - while (1) { - if (down_interruptible(&tsk->sema) == 0) { - - SMP_RD_BARRIER_DEPENDS(); - if (tsk->terminated) { - break; - } - - /* Call bus dpc unless it indicated down (then clean stop) */ - if (dhd->pub.busstate != DHD_BUS_DOWN) { - if (dhd_bus_dpc(dhd->pub.bus)) { - up(&tsk->sema); - } - else { - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } - } else { - if (dhd->pub.up) - dhd_bus_stop(dhd->pub.bus, TRUE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } - } - else - break; - } - - complete_and_exit(&tsk->completed, 0); -} -#endif /* DHDTHREAD */ - -static void -dhd_dpc(ulong data) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)data; - - /* this (tasklet) can be scheduled in dhd_sched_dpc[dhd_linux.c] - * down below , wake lock is set, - * the tasklet is initialized in dhd_attach() - */ - /* Call bus dpc unless it indicated down (then clean stop) */ - if (dhd->pub.busstate != DHD_BUS_DOWN) { - if (dhd_bus_dpc(dhd->pub.bus)) - tasklet_schedule(&dhd->tasklet); - else - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } else { - dhd_bus_stop(dhd->pub.bus, TRUE); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - } -} - -void -dhd_sched_dpc(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - - DHD_OS_WAKE_LOCK(dhdp); -#ifdef DHDTHREAD - if (dhd->thr_dpc_ctl.thr_pid >= 0) { - up(&dhd->thr_dpc_ctl.sema); - return; - } -#endif /* DHDTHREAD */ - - tasklet_schedule(&dhd->tasklet); -} - -#ifdef TOE -/* Retrieve current toe component enables, which are kept as a bitmap in toe_ol iovar */ -static int -dhd_toe_get(dhd_info_t *dhd, int ifidx, uint32 *toe_ol) -{ - wl_ioctl_t ioc; - char buf[32]; - int ret; - - memset(&ioc, 0, sizeof(ioc)); - - ioc.cmd = WLC_GET_VAR; - ioc.buf = buf; - ioc.len = (uint)sizeof(buf); - ioc.set = FALSE; - - strcpy(buf, "toe_ol"); - if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { - /* Check for older dongle image that doesn't support toe_ol */ - if (ret == -EIO) { - DHD_ERROR(("%s: toe not supported by device\n", - dhd_ifname(&dhd->pub, ifidx))); - return -EOPNOTSUPP; - } - - DHD_INFO(("%s: could not get toe_ol: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); - return ret; - } - - memcpy(toe_ol, buf, sizeof(uint32)); - return 0; -} - -/* Set current toe component enables in toe_ol iovar, and set toe global enable iovar */ -static int -dhd_toe_set(dhd_info_t *dhd, int ifidx, uint32 toe_ol) -{ - wl_ioctl_t ioc; - char buf[32]; - int toe, ret; - - memset(&ioc, 0, sizeof(ioc)); - - ioc.cmd = WLC_SET_VAR; - ioc.buf = buf; - ioc.len = (uint)sizeof(buf); - ioc.set = TRUE; - - /* Set toe_ol as requested */ - - strcpy(buf, "toe_ol"); - memcpy(&buf[sizeof("toe_ol")], &toe_ol, sizeof(uint32)); - - if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { - DHD_ERROR(("%s: could not set toe_ol: ret=%d\n", - dhd_ifname(&dhd->pub, ifidx), ret)); - return ret; - } - - /* Enable toe globally only if any components are enabled. */ - - toe = (toe_ol != 0); - - strcpy(buf, "toe"); - memcpy(&buf[sizeof("toe")], &toe, sizeof(uint32)); - - if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { - DHD_ERROR(("%s: could not set toe: ret=%d\n", dhd_ifname(&dhd->pub, ifidx), ret)); - return ret; - } - - return 0; -} -#endif /* TOE */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) -static void -dhd_ethtool_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - - sprintf(info->driver, "wl"); - sprintf(info->version, "%lu", dhd->pub.drv_version); -} - -struct ethtool_ops dhd_ethtool_ops = { - .get_drvinfo = dhd_ethtool_get_drvinfo -}; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ - - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) -static int -dhd_ethtool(dhd_info_t *dhd, void *uaddr) -{ - struct ethtool_drvinfo info; - char drvname[sizeof(info.driver)]; - uint32 cmd; -#ifdef TOE - struct ethtool_value edata; - uint32 toe_cmpnt, csum_dir; - int ret; -#endif - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* all ethtool calls start with a cmd word */ - if (copy_from_user(&cmd, uaddr, sizeof (uint32))) - return -EFAULT; - - switch (cmd) { - case ETHTOOL_GDRVINFO: - /* Copy out any request driver name */ - if (copy_from_user(&info, uaddr, sizeof(info))) - return -EFAULT; - strncpy(drvname, info.driver, sizeof(info.driver)); - drvname[sizeof(info.driver)-1] = '\0'; - - /* clear struct for return */ - memset(&info, 0, sizeof(info)); - info.cmd = cmd; - - /* if dhd requested, identify ourselves */ - if (strcmp(drvname, "?dhd") == 0) { - sprintf(info.driver, "dhd"); - strcpy(info.version, EPI_VERSION_STR); - } - - /* otherwise, require dongle to be up */ - else if (!dhd->pub.up) { - DHD_ERROR(("%s: dongle is not up\n", __FUNCTION__)); - return -ENODEV; - } - - /* finally, report dongle driver type */ - else if (dhd->pub.iswl) - sprintf(info.driver, "wl"); - else - sprintf(info.driver, "xx"); - - sprintf(info.version, "%lu", dhd->pub.drv_version); - if (copy_to_user(uaddr, &info, sizeof(info))) - return -EFAULT; - DHD_CTL(("%s: given %*s, returning %s\n", __FUNCTION__, - (int)sizeof(drvname), drvname, info.driver)); - break; - -#ifdef TOE - /* Get toe offload components from dongle */ - case ETHTOOL_GRXCSUM: - case ETHTOOL_GTXCSUM: - if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) - return ret; - - csum_dir = (cmd == ETHTOOL_GTXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; - - edata.cmd = cmd; - edata.data = (toe_cmpnt & csum_dir) ? 1 : 0; - - if (copy_to_user(uaddr, &edata, sizeof(edata))) - return -EFAULT; - break; - - /* Set toe offload components in dongle */ - case ETHTOOL_SRXCSUM: - case ETHTOOL_STXCSUM: - if (copy_from_user(&edata, uaddr, sizeof(edata))) - return -EFAULT; - - /* Read the current settings, update and write back */ - if ((ret = dhd_toe_get(dhd, 0, &toe_cmpnt)) < 0) - return ret; - - csum_dir = (cmd == ETHTOOL_STXCSUM) ? TOE_TX_CSUM_OL : TOE_RX_CSUM_OL; - - if (edata.data != 0) - toe_cmpnt |= csum_dir; - else - toe_cmpnt &= ~csum_dir; - - if ((ret = dhd_toe_set(dhd, 0, toe_cmpnt)) < 0) - return ret; - - /* If setting TX checksum mode, tell Linux the new mode */ - if (cmd == ETHTOOL_STXCSUM) { - if (edata.data) - dhd->iflist[0]->net->features |= NETIF_F_IP_CSUM; - else - dhd->iflist[0]->net->features &= ~NETIF_F_IP_CSUM; - } - - break; -#endif /* TOE */ - - default: - return -EOPNOTSUPP; - } - - return 0; -} -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ - -static bool dhd_check_hang(struct net_device *net, dhd_pub_t *dhdp, int error) -{ - dhd_info_t * dhd; - - if (!dhdp) - return FALSE; - - dhd = (dhd_info_t *)dhdp->info; - if (dhd->thr_sysioc_ctl.thr_pid <0) { - DHD_ERROR(("%s : skipped due to negative pid - unloading?\n", __FUNCTION__)); - return FALSE; - } - - if ((error == -ETIMEDOUT) || (error == -EREMOTEIO) - || ((dhdp->busstate == DHD_BUS_DOWN)&&(!dhdp->dongle_reset))) { - DHD_ERROR(("%s: Event HANG send up due to re=%d te=%d e=%d s=%d\n", __FUNCTION__, - dhdp->rxcnt_timeout, dhdp->txcnt_timeout, error, dhdp->busstate)); - net_os_send_hang_message(net); - return TRUE; - } - return FALSE; -} - -static int -dhd_ioctl_entry(struct net_device *net, struct ifreq *ifr, int cmd) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - dhd_ioctl_t ioc; - int bcmerror = 0; - int buflen = 0; - void *buf = NULL; - uint driver = 0; - int ifidx; - int ret; - - DHD_OS_WAKE_LOCK(&dhd->pub); - - /* send to dongle only if we are not waiting for reload already */ - if (dhd->pub.hang_was_sent) { - DHD_ERROR(("%s: HANG was sent up earlier\n", __FUNCTION__)); - DHD_OS_WAKE_LOCK_TIMEOUT_ENABLE(&dhd->pub, DHD_EVENT_TIMEOUT_MS); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return OSL_ERROR(BCME_DONGLE_DOWN); - } - - ifidx = dhd_net2idx(dhd, net); - DHD_TRACE(("%s: ifidx %d, cmd 0x%04x\n", __FUNCTION__, ifidx, cmd)); - - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s: BAD IF\n", __FUNCTION__)); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return -1; - } - -#if defined(CONFIG_WIRELESS_EXT) - /* linux wireless extensions */ - if ((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) { - /* may recurse, do NOT lock */ - ret = wl_iw_ioctl(net, ifr, cmd); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return ret; - } -#endif /* defined(CONFIG_WIRELESS_EXT) */ - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) - if (cmd == SIOCETHTOOL) { - ret = dhd_ethtool(dhd, (void*)ifr->ifr_data); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return ret; - } -#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 2) */ - - if (cmd == SIOCDEVPRIVATE+1) { - ret = wl_android_priv_cmd(net, ifr, cmd); - dhd_check_hang(net, &dhd->pub, ret); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return ret; - } - - if (cmd != SIOCDEVPRIVATE) { - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return -EOPNOTSUPP; - } - - memset(&ioc, 0, sizeof(ioc)); - - /* Copy the ioc control structure part of ioctl request */ - if (copy_from_user(&ioc, ifr->ifr_data, sizeof(wl_ioctl_t))) { - bcmerror = -BCME_BADADDR; - goto done; - } - - /* Copy out any buffer passed */ - if (ioc.buf) { - if (ioc.len == 0) { - DHD_TRACE(("%s: ioc.len=0, returns BCME_BADARG \n", __FUNCTION__)); - bcmerror = -BCME_BADARG; - goto done; - } - buflen = MIN(ioc.len, DHD_IOCTL_MAXLEN); - /* optimization for direct ioctl calls from kernel */ - /* - if (segment_eq(get_fs(), KERNEL_DS)) { - buf = ioc.buf; - } else { - */ - { - if (!(buf = (char*)MALLOC(dhd->pub.osh, buflen))) { - bcmerror = -BCME_NOMEM; - goto done; - } - if (copy_from_user(buf, ioc.buf, buflen)) { - bcmerror = -BCME_BADADDR; - goto done; - } - } - } - - /* To differentiate between wl and dhd read 4 more byes */ - if ((copy_from_user(&driver, (char *)ifr->ifr_data + sizeof(wl_ioctl_t), - sizeof(uint)) != 0)) { - bcmerror = -BCME_BADADDR; - goto done; - } - - if (!capable(CAP_NET_ADMIN)) { - bcmerror = -BCME_EPERM; - goto done; - } - - /* check for local dhd ioctl and handle it */ - if (driver == DHD_IOCTL_MAGIC) { - bcmerror = dhd_ioctl((void *)&dhd->pub, &ioc, buf, buflen); - if (bcmerror) - dhd->pub.bcmerror = bcmerror; - goto done; - } - - /* send to dongle (must be up, and wl). */ - if (dhd->pub.busstate != DHD_BUS_DATA) { - bcmerror = BCME_DONGLE_DOWN; - goto done; - } - - if (!dhd->pub.iswl) { - bcmerror = BCME_DONGLE_DOWN; - goto done; - } - - /* - * Flush the TX queue if required for proper message serialization: - * Intercept WLC_SET_KEY IOCTL - serialize M4 send and set key IOCTL to - * prevent M4 encryption and - * intercept WLC_DISASSOC IOCTL - serialize WPS-DONE and WLC_DISASSOC IOCTL to - * prevent disassoc frame being sent before WPS-DONE frame. - */ - if (ioc.cmd == WLC_SET_KEY || - (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL && - strncmp("wsec_key", ioc.buf, 9) == 0) || - (ioc.cmd == WLC_SET_VAR && ioc.buf != NULL && - strncmp("bsscfg:wsec_key", ioc.buf, 15) == 0) || - ioc.cmd == WLC_DISASSOC) - dhd_wait_pend8021x(net); - -#ifdef WLMEDIA_HTSF - if (ioc.buf) { - /* short cut wl ioctl calls here */ - if (strcmp("htsf", ioc.buf) == 0) { - dhd_ioctl_htsf_get(dhd, 0); - return BCME_OK; - } - - if (strcmp("htsflate", ioc.buf) == 0) { - if (ioc.set) { - memset(ts, 0, sizeof(tstamp_t)*TSMAX); - memset(&maxdelayts, 0, sizeof(tstamp_t)); - maxdelay = 0; - tspktcnt = 0; - maxdelaypktno = 0; - memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); - } else { - dhd_dump_latency(); - } - return BCME_OK; - } - if (strcmp("htsfclear", ioc.buf) == 0) { - memset(&vi_d1.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d2.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d3.bin, 0, sizeof(uint32)*NUMBIN); - memset(&vi_d4.bin, 0, sizeof(uint32)*NUMBIN); - htsf_seqnum = 0; - return BCME_OK; - } - if (strcmp("htsfhis", ioc.buf) == 0) { - dhd_dump_htsfhisto(&vi_d1, "H to D"); - dhd_dump_htsfhisto(&vi_d2, "D to D"); - dhd_dump_htsfhisto(&vi_d3, "D to H"); - dhd_dump_htsfhisto(&vi_d4, "H to H"); - return BCME_OK; - } - if (strcmp("tsport", ioc.buf) == 0) { - if (ioc.set) { - memcpy(&tsport, ioc.buf + 7, 4); - } else { - DHD_ERROR(("current timestamp port: %d \n", tsport)); - } - return BCME_OK; - } - } -#endif /* WLMEDIA_HTSF */ - -#ifdef BCM_FD_AGGR - if ((ioc.cmd == WLC_SET_VAR || ioc.cmd == WLC_GET_VAR) && - ioc.buf != NULL && strncmp("rpc_", ioc.buf, 4) == 0) { - bcmerror = dhd_fdaggr_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); - goto done; - } -#endif - bcmerror = dhd_wl_ioctl(&dhd->pub, ifidx, (wl_ioctl_t *)&ioc, buf, buflen); - -done: - dhd_check_hang(net, &dhd->pub, bcmerror); - - if (!bcmerror && buf && ioc.buf) { - if (copy_to_user(ioc.buf, buf, buflen)) - bcmerror = -EFAULT; - } - - if (buf) - MFREE(dhd->pub.osh, buf, buflen); - - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - return OSL_ERROR(bcmerror); -} - -#ifdef WL_CFG80211 -static int -dhd_cleanup_virt_ifaces(dhd_info_t *dhd) -{ - int i = 1; /* Leave ifidx 0 [Primary Interface] */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - int rollback_lock = FALSE; -#endif - - DHD_TRACE(("%s: Enter \n", __func__)); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - /* release lock for unregister_netdev */ - if (rtnl_is_locked()) { - rtnl_unlock(); - rollback_lock = TRUE; - } -#endif - - for (i = 1; i < DHD_MAX_IFS; i++) { - if (dhd->iflist[i]) { - DHD_ERROR(("(WAR TRACE)Deleting IF: %d \n", i)); - if ((dhd->iflist[i]->state != DHD_IF_DEL) && - (dhd->iflist[i]->state != DHD_IF_DELETING)) { - dhd->iflist[i]->state = DHD_IF_DEL; - dhd->iflist[i]->idx = i; - dhd_net_if_lock_local(dhd); - dhd_op_if(dhd->iflist[i]); - dhd_net_if_unlock_local(dhd); - } - } - } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - if (rollback_lock) - rtnl_lock(); -#endif - - return 0; -} -#endif /* WL_CFG80211 */ - -#if defined(WL_CFG80211) && defined(CUSTOMER_HW_SAMSUNG) -/* CSP#505233: Flags to indicate if we distingish power off policy when - * user set the memu "Keep Wi-Fi on during sleep" to "Never" - */ -int sleep_never = 0; -#endif - -static int -dhd_stop(struct net_device *net) -{ - int ifidx; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); - DHD_OS_WAKE_LOCK(&dhd->pub); - DHD_TRACE(("%s: (WAR TRACE)Enter %p\n", __FUNCTION__, net)); - if (dhd->pub.up == 0) { - goto exit; - } - ifidx = dhd_net2idx(dhd, net); - BCM_REFERENCE(ifidx); - -#ifdef WL_CFG80211 - if (ifidx == 0) { - wl_cfg80211_down(NULL); - - /* - * For CFG80211: Clean up all the left over virtual interfaces - * when the primary Interface is brought down. [ifconfig wlan0 down] - */ - if ((dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) && - (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211)) { - dhd_cleanup_virt_ifaces(dhd); - } - } -#endif - -#ifdef PROP_TXSTATUS - dhd_wlfc_cleanup(&dhd->pub); -#endif - /* Set state and stop OS transmissions */ - dhd->pub.up = 0; - netif_stop_queue(net); - - /* Stop the protocol module */ - dhd_prot_stop(&dhd->pub); - -#if defined(WL_CFG80211) - if (ifidx == 0) { - if (!dhd_download_fw_on_driverload) - wl_android_wifi_off(net); -#ifdef CUSTOMER_HW_SAMSUNG - else { - /* CSP#505233: Flags to indicate if we distingish - * power off policy when user set the memu - * "Keep Wi-Fi on during sleep" to "Never" - */ - if (sleep_never) { - dhd_deepsleep(net, 1); - sleep_never = 0; - } - } -#endif /* CUSTOMER_HW_SAMSUNG */ - } -#endif /* WL_CFG80211 */ - dhd->pub.dongle_trap_occured = 0; - dhd->pub.hang_was_sent = 0; - dhd->pub.rxcnt_timeout = 0; - dhd->pub.txcnt_timeout = 0; - OLD_MOD_DEC_USE_COUNT; -exit: - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return 0; -} - -static int -dhd_open(struct net_device *net) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(net); -#ifdef TOE - uint32 toe_ol; -#endif - int ifidx; - int32 ret = 0; -#ifdef WL_CFG80211 - bool fw_changed = FALSE; -#endif - DHD_OS_WAKE_LOCK(&dhd->pub); - /* Update FW path if it was changed */ - if ((strlen(firmware_path) != 0) && (firmware_path[0] != '\0')) { - if (firmware_path[strlen(firmware_path)-1] == '\n') - firmware_path[strlen(firmware_path)-1] = '\0'; -#ifdef WL_CFG80211 - if (dhd_download_fw_on_driverload && - strcmp(fw_path, firmware_path)) - { - DHD_ERROR(("firmware path changed:%s --> %s\n", - fw_path, firmware_path)); - fw_changed = TRUE; - } -#endif /* WL_CFG80211 */ - strcpy(fw_path, firmware_path); -#if defined(BCM4334_CHECK_CHIP_REV) - strcpy(fw_down_path, fw_path); - strcat(fw_down_path, chipver_tag); -#endif - firmware_path[0] = '\0'; - } - -#if !defined(WL_CFG80211) - /* - * Force start if ifconfig_up gets called before START command - * We keep WEXT's wl_control_wl_start to provide backward compatibility - * This should be removed in the future - */ - wl_control_wl_start(net); -#endif - - ifidx = dhd_net2idx(dhd, net); - DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); - - if (ifidx < 0) { - DHD_ERROR(("%s: Error: called with invalid IF\n", __FUNCTION__)); - ret = -1; - goto exit; - } - - if (!dhd->iflist[ifidx] || dhd->iflist[ifidx]->state == DHD_IF_DEL) { - DHD_ERROR(("%s: Error: called when IF already deleted\n", __FUNCTION__)); - ret = -1; - goto exit; - } - - if (ifidx == 0) { - atomic_set(&dhd->pend_8021x_cnt, 0); -#if defined(WL_CFG80211) - DHD_ERROR(("\n%s\n", dhd_version)); - if (!dhd_download_fw_on_driverload) { - ret = wl_android_wifi_on(net); - if (ret != 0) { - DHD_ERROR(("wl_android_wifi_on failed (%d)\n", ret)); - goto exit; - } - } else { -#ifdef CUSTOMER_HW_SAMSUNG - /* CSP#505233: Flags to indicate if we distingish - * power off policy when user set the memu - * "Keep Wi-Fi on during sleep" to "Never" - */ - if (sleep_never) { - dhd_deepsleep(net, 0); - sleep_never = 0; - } else { -#endif /* CUSTOMER_HW_SAMSUNG */ - if (fw_changed) { - wl_android_wifi_off(net); - msleep(300); - ret = wl_android_wifi_on(net); - if (ret != 0) { - DHD_ERROR(("wl_android_wifi_on failed (%d)\n", ret)); - goto exit; - } - } -#ifdef CUSTOMER_HW_SAMSUNG - } -#endif /* CUSTOMER_HW_SAMSUNG */ - } -#endif /* WL_CFG80211 */ - - if (dhd->pub.busstate != DHD_BUS_DATA) { - - /* try to bring up bus */ - if ((ret = dhd_bus_start(&dhd->pub)) != 0) { - DHD_ERROR(("%s: failed with code %d\n", __FUNCTION__, ret)); - ret = -1; - goto exit; - } - - } - - /* dhd_prot_init has been called in dhd_bus_start or wl_android_wifi_on */ - memcpy(net->dev_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); - -#ifdef TOE - /* Get current TOE mode from dongle */ - if (dhd_toe_get(dhd, ifidx, &toe_ol) >= 0 && (toe_ol & TOE_TX_CSUM_OL) != 0) - dhd->iflist[ifidx]->net->features |= NETIF_F_IP_CSUM; - else - dhd->iflist[ifidx]->net->features &= ~NETIF_F_IP_CSUM; -#endif /* TOE */ - -#if defined(WL_CFG80211) - if (unlikely(wl_cfg80211_up(NULL))) { - DHD_ERROR(("%s: failed to bring up cfg80211\n", __FUNCTION__)); - ret = -1; - goto exit; - } -#endif /* WL_CFG80211 */ - } - - /* Allow transmit calls */ - netif_start_queue(net); - dhd->pub.up = 1; -#ifdef BCMDBGFS - dhd_dbg_init(&dhd->pub); -#endif - - OLD_MOD_INC_USE_COUNT; -exit: - DHD_OS_WAKE_UNLOCK(&dhd->pub); - return ret; -} - -int dhd_do_driver_init(struct net_device *net) -{ - dhd_info_t *dhd = NULL; - - if (!net) { - DHD_ERROR(("Primary Interface not initialized \n")); - return -EINVAL; - } - - dhd = *(dhd_info_t **)netdev_priv(net); - - /* If driver is already initialized, do nothing - */ - if (dhd->pub.busstate == DHD_BUS_DATA) { - DHD_TRACE(("Driver already Inititalized. Nothing to do")); - return 0; - } - - if (dhd_open(net) < 0) { - DHD_ERROR(("Driver Init Failed \n")); - return -1; - } - - return 0; -} - -osl_t * -dhd_osl_attach(void *pdev, uint bustype) -{ - return osl_attach(pdev, bustype, TRUE); -} - -void -dhd_osl_detach(osl_t *osh) -{ - if (MALLOCED(osh)) { - DHD_ERROR(("%s: MEMORY LEAK %d bytes\n", __FUNCTION__, MALLOCED(osh))); - } - osl_detach(osh); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - dhd_registration_check = FALSE; - up(&dhd_registration_sem); - up(&dhd_chipup_sem); -#endif -} - -int -dhd_add_if(dhd_info_t *dhd, int ifidx, void *handle, char *name, - uint8 *mac_addr, uint32 flags, uint8 bssidx) -{ - dhd_if_t *ifp; - - DHD_TRACE(("%s: idx %d, handle->%p\n", __FUNCTION__, ifidx, handle)); - - ASSERT(dhd && (ifidx < DHD_MAX_IFS)); - - ifp = dhd->iflist[ifidx]; - if (ifp != NULL) { - if (ifp->net != NULL) { - netif_stop_queue(ifp->net); - unregister_netdev(ifp->net); - free_netdev(ifp->net); - } - } else - if ((ifp = MALLOC(dhd->pub.osh, sizeof(dhd_if_t))) == NULL) { - DHD_ERROR(("%s: OOM - dhd_if_t\n", __FUNCTION__)); - return -ENOMEM; - } - - memset(ifp, 0, sizeof(dhd_if_t)); - ifp->event2cfg80211 = FALSE; - ifp->info = dhd; - dhd->iflist[ifidx] = ifp; - strncpy(ifp->name, name, IFNAMSIZ); - ifp->name[IFNAMSIZ] = '\0'; - if (mac_addr != NULL) - memcpy(&ifp->mac_addr, mac_addr, ETHER_ADDR_LEN); - - if (handle == NULL) { - ifp->state = DHD_IF_ADD; - ifp->idx = ifidx; - ifp->bssidx = bssidx; - ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); - up(&dhd->thr_sysioc_ctl.sema); - } else - ifp->net = (struct net_device *)handle; - if (ifidx == 0) { - ifp->event2cfg80211 = TRUE; - } - - return 0; -} - -void -dhd_del_if(dhd_info_t *dhd, int ifidx) -{ - dhd_if_t *ifp; - - DHD_TRACE(("%s: idx %d\n", __FUNCTION__, ifidx)); - - ASSERT(dhd && ifidx && (ifidx < DHD_MAX_IFS)); - ifp = dhd->iflist[ifidx]; - if (!ifp) { - DHD_ERROR(("%s: Null interface\n", __FUNCTION__)); - return; - } - - ifp->state = DHD_IF_DEL; - ifp->idx = ifidx; - ASSERT(dhd->thr_sysioc_ctl.thr_pid >= 0); - up(&dhd->thr_sysioc_ctl.sema); -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) -static struct net_device_ops dhd_ops_pri = { - .ndo_open = dhd_open, - .ndo_stop = dhd_stop, - .ndo_get_stats = dhd_get_stats, - .ndo_do_ioctl = dhd_ioctl_entry, - .ndo_start_xmit = dhd_start_xmit, - .ndo_set_mac_address = dhd_set_mac_address, - .ndo_set_multicast_list = dhd_set_multicast_list, -}; - -static struct net_device_ops dhd_ops_virt = { - .ndo_get_stats = dhd_get_stats, - .ndo_do_ioctl = dhd_ioctl_entry, - .ndo_start_xmit = dhd_start_xmit, - .ndo_set_mac_address = dhd_set_mac_address, - .ndo_set_multicast_list = dhd_set_multicast_list, -}; -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) */ - -dhd_pub_t * -dhd_attach(osl_t *osh, struct dhd_bus *bus, uint bus_hdrlen) -{ - dhd_info_t *dhd = NULL; - struct net_device *net = NULL; - - dhd_attach_states_t dhd_state = DHD_ATTACH_STATE_INIT; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#ifdef BCM4334_CHECK_CHIP_REV - DHD_ERROR(("CHIP VER = [0x%x]\n", g_chipver)); - if (g_chipver == 1) { - DHD_ERROR(("----- CHIP bcm4334_B0 -----\n")); - strcpy(chipver_tag, "_b0"); - } else if (g_chipver == 2) { - DHD_ERROR(("----- CHIP bcm4334_B1 -----\n")); - strcpy(chipver_tag, "_b1"); - } else if (g_chipver == 3) { - DHD_ERROR(("----- CHIP bcm4334_B2 -----\n")); - strcpy(chipver_tag, "_b2"); - } - else { - DHD_ERROR(("----- Invalid chip version -----\n")); - goto fail; - } -#endif /* BCM4334_CHECK_CHIP_REV */ - - /* updates firmware nvram path if it was provided as module parameters */ - if ((strlen(firmware_path) != 0) && (firmware_path[0] != '\0')) - strcpy(fw_path, firmware_path); - if ((strlen(nvram_path) != 0) && (nvram_path[0] != '\0')) - strcpy(nv_path, nvram_path); - - /* Allocate etherdev, including space for private structure */ - if (!(net = alloc_etherdev(sizeof(dhd)))) { - DHD_ERROR(("%s: OOM - alloc_etherdev\n", __FUNCTION__)); - goto fail; - } - dhd_state |= DHD_ATTACH_STATE_NET_ALLOC; - - /* Allocate primary dhd_info */ - if (!(dhd = MALLOC(osh, sizeof(dhd_info_t)))) { - DHD_ERROR(("%s: OOM - alloc dhd_info\n", __FUNCTION__)); - goto fail; - } - memset(dhd, 0, sizeof(dhd_info_t)); - -#ifdef DHDTHREAD - dhd->thr_dpc_ctl.thr_pid = DHD_PID_KT_TL_INVALID; - dhd->thr_wdt_ctl.thr_pid = DHD_PID_KT_INVALID; -#else - dhd->dhd_tasklet_create = FALSE; -#endif /* DHDTHREAD */ - dhd->thr_sysioc_ctl.thr_pid = DHD_PID_KT_INVALID; - dhd_state |= DHD_ATTACH_STATE_DHD_ALLOC; - - /* - * Save the dhd_info into the priv - */ - memcpy((void *)netdev_priv(net), &dhd, sizeof(dhd)); - dhd->pub.osh = osh; - - /* Link to info module */ - dhd->pub.info = dhd; - /* Link to bus module */ - dhd->pub.bus = bus; - dhd->pub.hdrlen = bus_hdrlen; - - /* Set network interface name if it was provided as module parameter */ - if (iface_name[0]) { - int len; - char ch; - strncpy(net->name, iface_name, IFNAMSIZ); - net->name[IFNAMSIZ - 1] = 0; - len = strlen(net->name); - ch = net->name[len - 1]; - if ((ch > '9' || ch < '0') && (len < IFNAMSIZ - 2)) - strcat(net->name, "%d"); - } - - if (dhd_add_if(dhd, 0, (void *)net, net->name, NULL, 0, 0) == DHD_BAD_IF) - goto fail; - dhd_state |= DHD_ATTACH_STATE_ADD_IF; - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - net->open = NULL; -#else - net->netdev_ops = NULL; -#endif - - sema_init(&dhd->proto_sem, 1); - -#ifdef PROP_TXSTATUS - spin_lock_init(&dhd->wlfc_spinlock); -#endif /* PROP_TXSTATUS */ - - /* Initialize other structure content */ - init_waitqueue_head(&dhd->ioctl_resp_wait); - init_waitqueue_head(&dhd->ctrl_wait); - - /* Initialize the spinlocks */ - spin_lock_init(&dhd->sdlock); - spin_lock_init(&dhd->txqlock); - spin_lock_init(&dhd->dhd_lock); - - /* Initialize Wakelock stuff */ - spin_lock_init(&dhd->wakelock_spinlock); - dhd->wakelock_counter = 0; - dhd->wakelock_timeout_enable = 0; -#ifdef CONFIG_HAS_WAKELOCK - wake_lock_init(&dhd->wl_wifi, WAKE_LOCK_SUSPEND, "wlan_wake"); - wake_lock_init(&dhd->wl_rxwake, WAKE_LOCK_SUSPEND, "wlan_rx_wake"); -#ifdef PNO_SUPPORT - wake_lock_init(&dhd->pub.pno_wakelock, WAKE_LOCK_SUSPEND, "pno_wake_lock"); -#endif -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - mutex_init(&dhd->dhd_net_if_mutex); -#endif - dhd_state |= DHD_ATTACH_STATE_WAKELOCKS_INIT; - - /* Attach and link in the protocol */ - if (dhd_prot_attach(&dhd->pub) != 0) { - DHD_ERROR(("dhd_prot_attach failed\n")); - goto fail; - } - dhd_state |= DHD_ATTACH_STATE_PROT_ATTACH; - -#ifdef WL_CFG80211 - /* Attach and link in the cfg80211 */ - if (unlikely(wl_cfg80211_attach(net, &dhd->pub))) { - DHD_ERROR(("wl_cfg80211_attach failed\n")); - goto fail; - } - - dhd_monitor_init(&dhd->pub); - dhd_state |= DHD_ATTACH_STATE_CFG80211; -#endif -#if defined(CONFIG_WIRELESS_EXT) - /* Attach and link in the iw */ - if (!(dhd_state & DHD_ATTACH_STATE_CFG80211)) { - if (wl_iw_attach(net, (void *)&dhd->pub) != 0) { - DHD_ERROR(("wl_iw_attach failed\n")); - goto fail; - } - dhd_state |= DHD_ATTACH_STATE_WL_ATTACH; - } -#endif /* defined(CONFIG_WIRELESS_EXT) */ - - - /* Set up the watchdog timer */ - init_timer(&dhd->timer); - dhd->timer.data = (ulong)dhd; - dhd->timer.function = dhd_watchdog; - -#ifdef DHDTHREAD - /* Initialize thread based operation and lock */ - sema_init(&dhd->sdsem, 1); - if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0)) { - dhd->threads_only = TRUE; - } - else { - dhd->threads_only = FALSE; - } - - if (dhd_dpc_prio >= 0) { - /* Initialize watchdog thread */ - PROC_START(dhd_watchdog_thread, dhd, &dhd->thr_wdt_ctl, 0); - } else { - dhd->thr_wdt_ctl.thr_pid = -1; - } - - /* Set up the bottom half handler */ - if (dhd_dpc_prio >= 0) { - /* Initialize DPC thread */ - PROC_START(dhd_dpc_thread, dhd, &dhd->thr_dpc_ctl, 0); - } else { - /* use tasklet for dpc */ - tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); - dhd->thr_dpc_ctl.thr_pid = -1; - } -#else - /* Set up the bottom half handler */ - tasklet_init(&dhd->tasklet, dhd_dpc, (ulong)dhd); - dhd->dhd_tasklet_create = TRUE; -#endif /* DHDTHREAD */ - - if (dhd_sysioc) { - PROC_START(_dhd_sysioc_thread, dhd, &dhd->thr_sysioc_ctl, 0); - } else { - dhd->thr_sysioc_ctl.thr_pid = -1; - } - dhd_state |= DHD_ATTACH_STATE_THREADS_CREATED; - - /* - * Save the dhd_info into the priv - */ - memcpy(netdev_priv(net), &dhd, sizeof(dhd)); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) - register_pm_notifier(&dhd_sleep_pm_notifier); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - -#ifdef CONFIG_HAS_EARLYSUSPEND - dhd->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 20; - dhd->early_suspend.suspend = dhd_early_suspend; - dhd->early_suspend.resume = dhd_late_resume; - register_early_suspend(&dhd->early_suspend); - dhd_state |= DHD_ATTACH_STATE_EARLYSUSPEND_DONE; -#endif - -#ifdef ARP_OFFLOAD_SUPPORT - dhd->pend_ipaddr = 0; - register_inetaddr_notifier(&dhd_notifier); -#endif /* ARP_OFFLOAD_SUPPORT */ - - dhd_state |= DHD_ATTACH_STATE_DONE; - dhd->dhd_state = dhd_state; - return &dhd->pub; - -fail: - if (dhd_state < DHD_ATTACH_STATE_DHD_ALLOC) { - if (net) free_netdev(net); - } else { - DHD_TRACE(("%s: Calling dhd_detach dhd_state 0x%x &dhd->pub %p\n", - __FUNCTION__, dhd_state, &dhd->pub)); - dhd->dhd_state = dhd_state; - dhd_detach(&dhd->pub); - dhd_free(&dhd->pub); - } - - return NULL; -} - -int -dhd_bus_start(dhd_pub_t *dhdp) -{ - int ret = -1; - dhd_info_t *dhd = (dhd_info_t*)dhdp->info; - unsigned long flags; - char *down_path; - - ASSERT(dhd); - - DHD_TRACE(("Enter %s:\n", __FUNCTION__)); - -#ifdef DHDTHREAD - if (dhd->threads_only) - dhd_os_sdlock(dhdp); -#endif /* DHDTHREAD */ - - - /* try to download image and nvram to the dongle */ - if ((dhd->pub.busstate == DHD_BUS_DOWN) && - (fw_path[0] != '\0') && - (nv_path[0] != '\0')) { - down_path = fw_path; -#if defined(BCM4334_CHECK_CHIP_REV) - strcpy(fw_down_path, fw_path); - strcat(fw_down_path, chipver_tag); - down_path = fw_down_path; -#endif - /* wake lock moved to dhdsdio_download_firmware */ - if (!(dhd_bus_download_firmware(dhd->pub.bus, dhd->pub.osh, - down_path, nv_path))) { - DHD_ERROR(("%s: dhdsdio_probe_download failed. firmware = %s nvram = %s\n", - __FUNCTION__, down_path, nv_path)); -#ifdef DHDTHREAD - if (dhd->threads_only) - dhd_os_sdunlock(dhdp); -#endif /* DHDTHREAD */ - return -1; - } - } - if (dhd->pub.busstate != DHD_BUS_LOAD) { -#ifdef DHDTHREAD - if (dhd->threads_only) - dhd_os_sdunlock(dhdp); -#endif /* DHDTHREAD */ - return -ENETDOWN; - } - - /* Start the watchdog timer */ - dhd->pub.tickcnt = 0; - dhd_os_wd_timer(&dhd->pub, dhd_watchdog_ms); - - /* Bring up the bus */ - if ((ret = dhd_bus_init(&dhd->pub, FALSE)) != 0) { - - DHD_ERROR(("%s, dhd_bus_init failed %d\n", __FUNCTION__, ret)); -#ifdef DHDTHREAD - if (dhd->threads_only) - dhd_os_sdunlock(dhdp); -#endif /* DHDTHREAD */ - return ret; - } -#if defined(OOB_INTR_ONLY) - /* Host registration for OOB interrupt */ - if (bcmsdh_register_oob_intr(dhdp)) { - /* deactivate timer and wait for the handler to finish */ - - flags = dhd_os_spin_lock(&dhd->pub); - dhd->wd_timer_valid = FALSE; - dhd_os_spin_unlock(&dhd->pub, flags); - del_timer_sync(&dhd->timer); - - DHD_ERROR(("%s Host failed to register for OOB\n", __FUNCTION__)); -#ifdef DHDTHREAD - if (dhd->threads_only) - dhd_os_sdunlock(dhdp); -#endif /* DHDTHREAD */ - return -ENODEV; - } - - /* Enable oob at firmware */ - dhd_enable_oob_intr(dhd->pub.bus, TRUE); -#endif /* defined(OOB_INTR_ONLY) */ - - /* If bus is not ready, can't come up */ - if (dhd->pub.busstate != DHD_BUS_DATA) { - flags = dhd_os_spin_lock(&dhd->pub); - dhd->wd_timer_valid = FALSE; - dhd_os_spin_unlock(&dhd->pub, flags); - del_timer_sync(&dhd->timer); - DHD_ERROR(("%s failed bus is not ready\n", __FUNCTION__)); -#ifdef DHDTHREAD - if (dhd->threads_only) - dhd_os_sdunlock(dhdp); -#endif /* DHDTHREAD */ - return -ENODEV; - } - -#ifdef DHDTHREAD - if (dhd->threads_only) - dhd_os_sdunlock(dhdp); -#endif /* DHDTHREAD */ - -#ifdef CUSTOMER_HW_SAMSUNG -#ifdef USE_CID_CHECK - dhd_check_module_cid(dhdp); -#endif -#ifdef GET_MAC_FROM_OTP - dhd_check_module_mac(dhdp); -#endif -#ifdef READ_MACADDR - dhd_read_macaddr(dhd, &dhd->pub.mac); -#endif -#ifdef RDWR_MACADDR - dhd_check_rdwr_macaddr(dhd, &dhd->pub, &dhd->pub.mac); -#endif -#ifdef RDWR_KORICS_MACADDR - dhd_write_rdwr_korics_macaddr(dhd, &dhd->pub.mac); -#endif -#endif /* CUSTOMER_HW_SAMSUNG */ - - /* Bus is ready, do any protocol initialization */ - if ((ret = dhd_prot_init(&dhd->pub)) < 0) - return ret; - -#ifdef CUSTOMER_HW_SAMSUNG -#ifdef RDWR_MACADDR - dhd_write_rdwr_macaddr(&dhd->pub.mac); -#endif -#ifdef WRITE_MACADDR - dhd_write_macaddr(&dhd->pub.mac); -#endif -#endif /* CUSTOMER_HW_SAMSUNG */ - -#ifdef ARP_OFFLOAD_SUPPORT - if (dhd->pend_ipaddr) { -#ifdef AOE_IP_ALIAS_SUPPORT - aoe_update_host_ipv4_table(&dhd->pub, dhd->pend_ipaddr, TRUE); -#endif /* AOE_IP_ALIAS_SUPPORT */ - dhd->pend_ipaddr = 0; - } -#endif /* ARP_OFFLOAD_SUPPORT */ - - return 0; -} - -#if !defined(AP) && defined(WLP2P) -/* For Android ICS MR2 release, the concurrent mode is enabled by default and the firmware - * name would be fw_bcmdhd.bin. So we need to determine whether P2P is enabled in the STA - * firmware and accordingly enable concurrent mode (Apply P2P settings). SoftAP firmware - * would still be named as fw_bcmdhd_apsta. - */ -bool -dhd_concurrent_fw(dhd_pub_t *dhd) -{ - int i, ret = 0; - char buf[WLC_IOCTL_SMLEN]; - char *cap[] = {"p2p", "mchan", "dsta", NULL}; - if ((!op_mode) && (strstr(fw_path, "_p2p") == NULL) && - (strstr(fw_path, "_apsta") == NULL)) { - /* Given path is for the STA firmware. Check whether VSDB + P2P support - * is present in the firmware. If so, set mode as P2P (concurrent support). - */ - for (i = 0; cap[i] != NULL; ) { - memset(buf, 0, sizeof(buf)); - bcm_mkiovar(cap[i++], 0, 0, buf, sizeof(buf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), - FALSE, 0)) < 0) { - DHD_TRACE(("%s: Get VSDB Capability(%s) failed (error=%d)\n", - __FUNCTION__, cap[i-1], ret)); - return 0; - } else if (buf[0] != 1) { - DHD_TRACE(("VSDB(%s) is not supported , ret : %d\n", - cap[i-1], buf[0])); - return 0; - } - } - return 1; - } - return 0; -} -#endif /* !defined(AP) && defined(WLP2P) */ -int -dhd_preinit_ioctls(dhd_pub_t *dhd) -{ - int ret = 0; - char eventmask[WL_EVENTING_MASK_LEN]; - char iovbuf[WL_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ - - uint up = 0; - uint power_mode = PM_FAST; - uint32 dongle_align = DHD_SDALIGN; -#if defined(BCM4334_CHIP) - uint32 glom = 5; /* 2012.02.21 for perfomance */ - uint32 bcn_li_bcn = 1; -#elif defined(BCM43241_CHIP) - uint32 glom = 1; -#else - uint32 glom = 0; -#endif -#if defined(VSDB) || defined(ROAM_ENABLE) - uint bcn_timeout = 8; -#else - uint bcn_timeout = 4; -#endif - uint retry_max = 3; -#if defined(ARP_OFFLOAD_SUPPORT) - int arpoe = 1; -#endif - int scan_assoc_time = DHD_SCAN_ACTIVE_TIME; - int scan_unassoc_time = 80; - int scan_passive_time = DHD_SCAN_PASSIVE_TIME; - char buf[WLC_IOCTL_SMLEN]; - char *ptr; - uint32 listen_interval = LISTEN_INTERVAL; /* Default Listen Interval in Beacons */ -#ifdef CUSTOMER_HW_SAMSUNG -#ifdef ROAM_ENABLE - uint roamvar = 0; - int roam_trigger[2] = {WL_AUTO_ROAM_TRIGGER, WLC_BAND_ALL}; - int roam_scan_period[2] = {10, WLC_BAND_ALL}; - int roam_delta[2] = {10, WLC_BAND_ALL}; - int roam_env_mode = AP_ENV_INDETERMINATE; -#ifdef FULL_ROAMING_SCAN_PERIOD_60_SEC - int roam_fullscan_period = 60; -#else /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ - int roam_fullscan_period = 120; -#endif /* FULL_ROAMING_SCAN_PERIOD_60_SEC */ -#else - uint roamvar = 1; -#endif /* ROAM_ENABLE */ -#ifdef WL_CFG80211 -#ifdef SOFTAP_DISABLE_WMM - uint32 wme = 0; -#endif /* SOFTAP_DISABLE_WMM */ - uint32 vlan_mode = 0; -#endif /* WL_CFG80211 */ -#endif /* CUSTOMER_HW_SAMSUNG */ -#if defined(SOFTAP) - uint dtim = 1; -#endif -#if (defined(AP) && !defined(WLP2P)) || (!defined(AP) && defined(WL_CFG80211)) - uint32 mpc = 0; /* Turn MPC off for AP/APSTA mode */ -#endif - -#if defined(AP) || defined(WLP2P) - uint32 apsta = 1; /* Enable APSTA mode */ - struct ether_addr p2p_ea; -#endif /* defined(AP) || defined(WLP2P) */ -#ifdef GET_CUSTOM_MAC_ENABLE - struct ether_addr ea_addr; -#endif /* GET_CUSTOM_MAC_ENABLE */ -#ifdef OKC_SUPPORT - uint32 okc = 1; -#endif /* OKC_SUPPORT */ - -#ifdef VLAN_MODE_OFF - int vlanmode = 0; -#endif /* VLAN_MODE_OFF */ -#ifdef BCM43241_CHIP - int mimo_bw_cap = 2; -#endif /* BCM43241_CHIP */ -#ifdef AUTOCOUNTRY - int autocountry = 1; -#endif -#ifdef VSDB - int interference_mode = 3; -#endif -#ifdef PROP_TXSTATUS - dhd->wlfc_enabled = FALSE; - /* enable WLFC only if the firmware is VSDB */ -#endif /* PROP_TXSTATUS */ - - DHD_TRACE(("Enter %s\n", __FUNCTION__)); - dhd->op_mode = 0; -#ifdef GET_CUSTOM_MAC_ENABLE - ret = dhd_custom_get_mac_address(ea_addr.octet); - if (!ret) { - memset(buf, 0, sizeof(buf)); - bcm_mkiovar("cur_etheraddr", (void *)&ea_addr, ETHER_ADDR_LEN, buf, sizeof(buf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); - if (ret < 0) { - DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); - return BCME_NOTUP; - } - } else { -#endif /* GET_CUSTOM_MAC_ENABLE */ - /* Get the default device MAC address directly from firmware */ - memset(buf, 0, sizeof(buf)); - bcm_mkiovar("cur_etheraddr", 0, 0, buf, sizeof(buf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), - FALSE, 0)) < 0) { - DHD_ERROR(("%s: can't get MAC address , error=%d\n", __FUNCTION__, ret)); - return BCME_NOTUP; - } - /* Update public MAC address after reading from Firmware */ - memcpy(dhd->mac.octet, buf, ETHER_ADDR_LEN); - -#ifdef GET_CUSTOM_MAC_ENABLE - } -#endif /* GET_CUSTOM_MAC_ENABLE */ - -#ifdef SET_RANDOM_MAC_SOFTAP - if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == 0x02)) { - uint rand_mac; - - srandom32((uint)jiffies); - rand_mac = random32(); - iovbuf[0] = 0x02; /* locally administered bit */ - iovbuf[1] = 0x1A; - iovbuf[2] = 0x11; - iovbuf[3] = (unsigned char)(rand_mac & 0x0F) | 0xF0; - iovbuf[4] = (unsigned char)(rand_mac >> 8); - iovbuf[5] = (unsigned char)(rand_mac >> 16); - - bcm_mkiovar("cur_etheraddr", (void *)iovbuf, ETHER_ADDR_LEN, buf, sizeof(buf)); - ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, buf, sizeof(buf), TRUE, 0); - if (ret < 0) { - DHD_ERROR(("%s: can't set MAC address , error=%d\n", __FUNCTION__, ret)); - } else - memcpy(dhd->mac.octet, iovbuf, ETHER_ADDR_LEN); - } -#endif /* SET_RANDOM_MAC_SOFTAP */ - - DHD_TRACE(("Firmware = %s\n", fw_path)); -#if !defined(AP) && defined(WLP2P) - /* Check if firmware with WFD support used */ - if ((!op_mode && strstr(fw_path, "_p2p") != NULL) || (op_mode == 0x04) || - (dhd_concurrent_fw(dhd))) { - bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, - iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s APSTA for WFD failed ret= %d\n", __FUNCTION__, ret)); - } else if (!dhd_concurrent_fw(dhd)) { - dhd->op_mode |= WFD_MASK; -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 0; -#endif /* (ARP_OFFLOAD_SUPPORT) */ - dhd_pkt_filter_enable = FALSE; - } - - memcpy(&p2p_ea, &dhd->mac, ETHER_ADDR_LEN); - ETHER_SET_LOCALADDR(&p2p_ea); - bcm_mkiovar("p2p_da_override", (char *)&p2p_ea, - ETHER_ADDR_LEN, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, - iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s p2p_da_override ret= %d\n", __FUNCTION__, ret)); - } else { - DHD_INFO(("dhd_preinit_ioctls: p2p_da_override succeeded\n")); - } - } -#endif /* (ARP_OFFLOAD_SUPPORT) */ - -#if !defined(AP) && defined(WL_CFG80211) - /* Check if firmware with HostAPD support used */ - if ((!op_mode && strstr(fw_path, "_apsta") != NULL) || (op_mode == 0x02)) { -#ifdef CUSTOMER_HW_SAMSUNG -#ifdef SOFTAP_DISABLE_WMM - /* WMM disable to avoid SoftAP hangup */ - bcm_mkiovar("wme", (char *)&wme, 4, - iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s disable wme for HostAPD" - " failed %d\n", __FUNCTION__, ret)); - } -#endif /* SOFTAP_DISABLE_WMM */ - - /* VLAN tagging disable to avoid SoftAP hangup */ - bcm_mkiovar("vlan_mode", (char *)&vlan_mode, 4, - iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s disable VLAN tagging for" - " HostAPD failed %d\n", - __FUNCTION__, ret)); - } -#endif /* CUSTOMER_HW_SAMSUNG */ - /* Turn off MPC in AP mode */ - bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, - sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s mpc for HostAPD failed %d\n", __FUNCTION__, ret)); - } else { - dhd->op_mode |= HOSTAPD_MASK; -#if defined(ARP_OFFLOAD_SUPPORT) - arpoe = 0; -#endif /* (ARP_OFFLOAD_SUPPORT) */ - dhd_pkt_filter_enable = FALSE; - } - } -#endif /* (ARP_OFFLOAD_SUPPORT) */ - - if ((dhd->op_mode != WFD_MASK) && (dhd->op_mode != HOSTAPD_MASK)) { - /* STA only operation mode */ - dhd->op_mode |= STA_MASK; - dhd_pkt_filter_enable = TRUE; - if (dhd_concurrent_fw(dhd)) { - dhd->op_mode |= WFD_MASK; - } - } - - DHD_ERROR(("Firmware up: op_mode=%d", dhd->op_mode)); - - /* Set Country code */ - if (dhd->dhd_cspec.ccode[0] != 0) { - bcm_mkiovar("country", (char *)&dhd->dhd_cspec, - sizeof(wl_country_t), iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s: country code setting failed\n", __FUNCTION__)); - } - - /* Set Listen Interval */ - bcm_mkiovar("assoc_listen", (char *)&listen_interval, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) - DHD_ERROR(("%s assoc_listen failed %d\n", __FUNCTION__, ret)); - -#ifdef CUSTOMER_HW_SAMSUNG - /* Disable built-in roaming to allowed ext supplicant to take care of roaming */ - bcm_mkiovar("roam_off", (char *)&roamvar, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - -#ifdef ROAM_ENABLE - dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_TRIGGER, roam_trigger, sizeof(roam_trigger), TRUE, 0); - dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_SCAN_PERIOD, roam_scan_period, - sizeof(roam_scan_period), TRUE, 0); - dhd_wl_ioctl_cmd(dhd, WLC_SET_ROAM_DELTA, roam_delta, sizeof(roam_delta), TRUE, 0); - bcm_mkiovar("fullroamperiod", (char *)&roam_fullscan_period, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - if (roam_trigger[0] == WL_AUTO_ROAM_TRIGGER) { - bcm_mkiovar("roam_env_detection", (char *)&roam_env_mode, 4, iovbuf, sizeof(iovbuf)); - if (dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0) == BCME_OK) - dhd->roam_env_detection = TRUE; - else - dhd->roam_env_detection = FALSE; - } -#endif - -#ifdef OKC_SUPPORT - bcm_mkiovar("okc_enable", (char *)&okc, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif - -#ifdef AUTOCOUNTRY - bcm_mkiovar("autocountry", (char *)&autocountry, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif - -#endif /* CUSTOMER_HW_SAMSUNG */ - -#ifdef CONFIG_CONTROL_PM - sec_control_pm(dhd, &power_mode); -#else - /* Set PowerSave mode */ - dhd_wl_ioctl_cmd(dhd, WLC_SET_PM, (char *)&power_mode, sizeof(power_mode), TRUE, 0); -#endif - - /* Match Host and Dongle rx alignment */ - bcm_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - - /* disable glom option per default */ - bcm_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - - /* Setup timeout if Beacons are lost and roam is off to report link down */ - bcm_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - /* Setup assoc_retry_max count to reconnect target AP in dongle */ - bcm_mkiovar("assoc_retry_max", (char *)&retry_max, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#if defined(AP) && !defined(WLP2P) - /* Turn off MPC in AP mode */ - bcm_mkiovar("mpc", (char *)&mpc, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - bcm_mkiovar("apsta", (char *)&apsta, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* defined(AP) && !defined(WLP2P) */ - -#ifdef BCM43241_CHIP - bcm_mkiovar("mimo_bw_cap", (char *)&mimo_bw_cap, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif - -#if defined(SOFTAP) - if (ap_fw_loaded == TRUE) { - dhd_wl_ioctl_cmd(dhd, WLC_SET_DTIMPRD, (char *)&dtim, sizeof(dtim), TRUE, 0); - } -#endif - -#if defined(KEEP_ALIVE) - { - /* Set Keep Alive : be sure to use FW with -keepalive */ - int res; - -#if defined(SOFTAP) - if (ap_fw_loaded == FALSE) -#endif - if ((dhd->op_mode & HOSTAPD_MASK) != HOSTAPD_MASK) { - if ((res = dhd_keep_alive_onoff(dhd)) < 0) - DHD_ERROR(("%s set keeplive failed %d\n", - __FUNCTION__, res)); - } - } -#endif /* defined(KEEP_ALIVE) */ - - /* Read event_msgs mask */ - bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) { - DHD_ERROR(("%s read Event mask failed %d\n", __FUNCTION__, ret)); - goto done; - } - bcopy(iovbuf, eventmask, WL_EVENTING_MASK_LEN); - - /* Setup event_msgs */ - setbit(eventmask, WLC_E_SET_SSID); - setbit(eventmask, WLC_E_PRUNE); - setbit(eventmask, WLC_E_AUTH); - setbit(eventmask, WLC_E_REASSOC); - setbit(eventmask, WLC_E_REASSOC_IND); - setbit(eventmask, WLC_E_DEAUTH); - setbit(eventmask, WLC_E_DEAUTH_IND); - setbit(eventmask, WLC_E_DISASSOC_IND); - setbit(eventmask, WLC_E_DISASSOC); - setbit(eventmask, WLC_E_JOIN); - setbit(eventmask, WLC_E_ASSOC_IND); - setbit(eventmask, WLC_E_PSK_SUP); - setbit(eventmask, WLC_E_LINK); - setbit(eventmask, WLC_E_NDIS_LINK); - setbit(eventmask, WLC_E_MIC_ERROR); - setbit(eventmask, WLC_E_ASSOC_REQ_IE); - setbit(eventmask, WLC_E_ASSOC_RESP_IE); -#ifndef WL_CFG80211 - setbit(eventmask, WLC_E_PMKID_CACHE); -#endif - setbit(eventmask, WLC_E_TXFAIL); - setbit(eventmask, WLC_E_JOIN_START); - setbit(eventmask, WLC_E_SCAN_COMPLETE); -#ifdef WLMEDIA_HTSF - setbit(eventmask, WLC_E_HTSFSYNC); -#endif /* WLMEDIA_HTSF */ -#ifdef PNO_SUPPORT - setbit(eventmask, WLC_E_PFN_NET_FOUND); -#endif /* PNO_SUPPORT */ -#ifdef USE_FW_TRACE - setbit(eventmask, WLC_E_TRACE); -#endif - /* enable dongle roaming event */ - setbit(eventmask, WLC_E_ROAM); -#ifdef WL_CFG80211 - setbit(eventmask, WLC_E_ESCAN_RESULT); - if ((dhd->op_mode & WFD_MASK) == WFD_MASK) { - setbit(eventmask, WLC_E_ACTION_FRAME_RX); - setbit(eventmask, WLC_E_ACTION_FRAME_COMPLETE); - setbit(eventmask, WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE); - setbit(eventmask, WLC_E_P2P_DISC_LISTEN_COMPLETE); - } -#endif /* WL_CFG80211 */ -#ifdef OKC_DEBUG - setbit(eventmask, WLC_E_ROAM_START); -#endif /* OKC_DEBUG */ -#ifdef CUSTOMER_HW_SAMSUNG - clrbit(eventmask, WLC_E_TXFAIL); -#endif - - /* Write updated Event mask */ - bcm_mkiovar("event_msgs", eventmask, WL_EVENTING_MASK_LEN, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0)) < 0) { - DHD_ERROR(("%s Set Event mask failed %d\n", __FUNCTION__, ret)); - goto done; - } - - dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_CHANNEL_TIME, (char *)&scan_assoc_time, - sizeof(scan_assoc_time), TRUE, 0); - dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_UNASSOC_TIME, (char *)&scan_unassoc_time, - sizeof(scan_unassoc_time), TRUE, 0); - dhd_wl_ioctl_cmd(dhd, WLC_SET_SCAN_PASSIVE_TIME, (char *)&scan_passive_time, - sizeof(scan_passive_time), TRUE, 0); - -#ifdef ARP_OFFLOAD_SUPPORT - /* Set and enable ARP offload feature for STA only */ -#if defined(SOFTAP) - if (arpoe && !ap_fw_loaded) { -#else - if (arpoe) { -#endif - dhd_arp_offload_enable(dhd, arpoe); - dhd_arp_offload_set(dhd, dhd_arp_mode); - } else { - dhd_arp_offload_enable(dhd, FALSE); - dhd_arp_offload_set(dhd, 0); - } -#endif /* ARP_OFFLOAD_SUPPORT */ - -#ifdef PKT_FILTER_SUPPORT - /* Setup defintions for pktfilter , enable in suspend */ - dhd->pktfilter_count = 1; - dhd->pktfilter[0] = "100 0 0 0 0x01 0x00"; - -#if defined(SOFTAP) - if (ap_fw_loaded) { - int i; - for (i = 0; i < dhd->pktfilter_count; i++) { - dhd_pktfilter_offload_enable(dhd, dhd->pktfilter[i], - 0, dhd_master_mode); - } - } -#endif /* defined(SOFTAP) */ - if (dhd->pktfilter_count) { - int i; - - for (i = 0; i < dhd->pktfilter_count; i++) - dhd_pktfilter_offload_set(dhd, dhd->pktfilter[i]); - } -#endif /* PKT_FILTER_SUPPORT */ - -#ifdef VLAN_MODE_OFF - bcm_mkiovar("vlan_mode", (char *)&vlanmode, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif /* VLAN_MODE_OFF */ -#ifdef GLOBALCONFIG_WLAN_COUNTRY_CODE - if (dhd_customer_set_country(dhd) < 0) - DHD_ERROR(("%s: can't set country \n", __FUNCTION__)); -#endif - - /* Force STA UP */ - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_UP, (char *)&up, sizeof(up), TRUE, 0)) < 0) { - DHD_ERROR(("%s Setting WL UP failed %d\n", __FUNCTION__, ret)); - goto done; - } -#ifdef VSDB - dhd_wl_ioctl_cmd(dhd, WLC_SET_INTERFERENCE_MODE, (int *)&interference_mode, sizeof(int), TRUE, 0); -#endif - -#ifdef BCM4334_CHIP - bcm_mkiovar("bcn_li_bcn", (char *)&bcn_li_bcn, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhd, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); -#endif - - /* query for 'ver' to get version info from firmware */ - memset(buf, 0, sizeof(buf)); - ptr = buf; - bcm_mkiovar("ver", (char *)&buf, 4, buf, sizeof(buf)); - if ((ret = dhd_wl_ioctl_cmd(dhd, WLC_GET_VAR, buf, sizeof(buf), FALSE, 0)) < 0) - DHD_ERROR(("%s failed %d\n", __FUNCTION__, ret)); - else { - bcmstrtok(&ptr, "\n", 0); - /* Print fw version info */ - DHD_ERROR(("Firmware version = %s\n", buf)); - } - -done: - return ret; -} - - -int -dhd_iovar(dhd_pub_t *pub, int ifidx, char *name, char *cmd_buf, uint cmd_len, int set) -{ - char buf[strlen(name) + 1 + cmd_len]; - int len = sizeof(buf); - wl_ioctl_t ioc; - int ret; - - len = bcm_mkiovar(name, cmd_buf, cmd_len, buf, len); - - memset(&ioc, 0, sizeof(ioc)); - - ioc.cmd = set? WLC_SET_VAR : WLC_GET_VAR; - ioc.buf = buf; - ioc.len = len; - ioc.set = TRUE; - - ret = dhd_wl_ioctl(pub, ifidx, &ioc, ioc.buf, ioc.len); - if (!set && ret >= 0) - memcpy(cmd_buf, buf, cmd_len); - - return ret; -} - -int dhd_change_mtu(dhd_pub_t *dhdp, int new_mtu, int ifidx) -{ - struct dhd_info *dhd = dhdp->info; - struct net_device *dev = NULL; - - ASSERT(dhd && dhd->iflist[ifidx]); - dev = dhd->iflist[ifidx]->net; - ASSERT(dev); - - if (netif_running(dev)) { - DHD_ERROR(("%s: Must be down to change its MTU", dev->name)); - return BCME_NOTDOWN; - } - -#define DHD_MIN_MTU 1500 -#define DHD_MAX_MTU 1752 - - if ((new_mtu < DHD_MIN_MTU) || (new_mtu > DHD_MAX_MTU)) { - DHD_ERROR(("%s: MTU size %d is invalid.\n", __FUNCTION__, new_mtu)); - return BCME_BADARG; - } - - dev->mtu = new_mtu; - return 0; -} - -#ifdef ARP_OFFLOAD_SUPPORT -/* add or remove AOE host ip(s) (up to 8 IPs on the interface) */ -void -aoe_update_host_ipv4_table(dhd_pub_t *dhd_pub, u32 ipa, bool add) -{ - u32 ipv4_buf[MAX_IPV4_ENTRIES]; /* temp save for AOE host_ip table */ - int i; - int ret; - - bzero(ipv4_buf, sizeof(ipv4_buf)); - - /* display what we've got */ - ret = dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf)); - DHD_ARPOE(("%s: hostip table read from Dongle:\n", __FUNCTION__)); -#ifdef AOE_DBG - dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ -#endif - /* now we saved hoste_ip table, clr it in the dongle AOE */ - dhd_aoe_hostip_clr(dhd_pub); - - if (ret) { - DHD_ERROR(("%s failed\n", __FUNCTION__)); - return; - } - - for (i = 0; i < MAX_IPV4_ENTRIES; i++) { - if (add && (ipv4_buf[i] == 0)) { - ipv4_buf[i] = ipa; - add = FALSE; /* added ipa to local table */ - DHD_ARPOE(("%s: Saved new IP in temp arp_hostip[%d]\n", - __FUNCTION__, i)); - } else if (ipv4_buf[i] == ipa) { - ipv4_buf[i] = 0; - DHD_ARPOE(("%s: removed IP:%x from temp table %d\n", - __FUNCTION__, ipa, i)); - } - - if (ipv4_buf[i] != 0) { - /* add back host_ip entries from our local cache */ - dhd_arp_offload_add_ip(dhd_pub, ipv4_buf[i]); - DHD_ARPOE(("%s: added IP:%x to dongle arp_hostip[%d]\n\n", - __FUNCTION__, ipv4_buf[i], i)); - } - } -#ifdef AOE_DBG - /* see the resulting hostip table */ - dhd_arp_get_arp_hostip_table(dhd_pub, ipv4_buf, sizeof(ipv4_buf)); - DHD_ARPOE(("%s: read back arp_hostip table:\n", __FUNCTION__)); - dhd_print_buf(ipv4_buf, 32, 4); /* max 8 IPs 4b each */ -#endif -} - -static int dhd_device_event(struct notifier_block *this, - unsigned long event, - void *ptr) -{ - struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; - - dhd_info_t *dhd; - dhd_pub_t *dhd_pub; - - if (!ifa) - return NOTIFY_DONE; - - dhd = *(dhd_info_t **)netdev_priv(ifa->ifa_dev->dev); - dhd_pub = &dhd->pub; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)) - if (ifa->ifa_dev->dev->netdev_ops == &dhd_ops_pri) { -#else - if (ifa->ifa_dev->dev) { -#endif - switch (event) { - case NETDEV_UP: - DHD_ARPOE(("%s: [%s] Up IP: 0x%x\n", - __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - - if (dhd->pub.busstate != DHD_BUS_DATA) { - DHD_ERROR(("%s: bus not ready, exit\n", __FUNCTION__)); - if (dhd->pend_ipaddr) { - DHD_ERROR(("%s: overwrite pending ipaddr: 0x%x\n", - __FUNCTION__, dhd->pend_ipaddr)); - } - dhd->pend_ipaddr = ifa->ifa_address; - break; - } - -#ifdef AOE_IP_ALIAS_SUPPORT - if ((dhd_pub->op_mode & HOSTAPD_MASK) != HOSTAPD_MASK) { - if (ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a) { - /* 0x3a = ':' */ - DHD_ARPOE(("%s:add aliased IP to AOE hostip cache\n", - __FUNCTION__)); - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); - } - else - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, TRUE); - } -#endif - break; - - case NETDEV_DOWN: - DHD_ARPOE(("%s: [%s] Down IP: 0x%x\n", - __FUNCTION__, ifa->ifa_label, ifa->ifa_address)); - dhd->pend_ipaddr = 0; -#ifdef AOE_IP_ALIAS_SUPPORT - if ((dhd_pub->op_mode & HOSTAPD_MASK) != HOSTAPD_MASK) { - if (!(ifa->ifa_label[strlen(ifa->ifa_label)-2] == 0x3a)) { - /* 0x3a = ':' */ - DHD_ARPOE(("%s: primary interface is down, AOE clr all\n", - __FUNCTION__)); - dhd_aoe_hostip_clr(&dhd->pub); - dhd_aoe_arp_clr(&dhd->pub); - } else - aoe_update_host_ipv4_table(dhd_pub, ifa->ifa_address, FALSE); - } -#else - dhd_aoe_hostip_clr(&dhd->pub); - dhd_aoe_arp_clr(&dhd->pub); -#endif - break; - - default: - DHD_ARPOE(("%s: do noting for [%s] Event: %lu\n", - __func__, ifa->ifa_label, event)); - break; - } - } - return NOTIFY_DONE; -} -#endif /* ARP_OFFLOAD_SUPPORT */ -int -dhd_net_attach(dhd_pub_t *dhdp, int ifidx) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - struct net_device *net = NULL; - int err = 0; - uint8 temp_addr[ETHER_ADDR_LEN] = { 0x00, 0x90, 0x4c, 0x11, 0x22, 0x33 }; - - DHD_TRACE(("%s: ifidx %d\n", __FUNCTION__, ifidx)); - - ASSERT(dhd && dhd->iflist[ifidx]); - - net = dhd->iflist[ifidx]->net; - ASSERT(net); - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - ASSERT(!net->open); - net->get_stats = dhd_get_stats; - net->do_ioctl = dhd_ioctl_entry; - net->hard_start_xmit = dhd_start_xmit; - net->set_mac_address = dhd_set_mac_address; - net->set_multicast_list = dhd_set_multicast_list; - net->open = net->stop = NULL; -#else - ASSERT(!net->netdev_ops); - net->netdev_ops = &dhd_ops_virt; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - - /* Ok, link into the network layer... */ - if (ifidx == 0) { - /* - * device functions for the primary interface only - */ -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - net->open = dhd_open; - net->stop = dhd_stop; -#else - net->netdev_ops = &dhd_ops_pri; -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) */ - memcpy(temp_addr, dhd->pub.mac.octet, ETHER_ADDR_LEN); - } else { - /* - * We have to use the primary MAC for virtual interfaces - */ - memcpy(temp_addr, dhd->iflist[ifidx]->mac_addr, ETHER_ADDR_LEN); - /* - * Android sets the locally administered bit to indicate that this is a - * portable hotspot. This will not work in simultaneous AP/STA mode, - * nor with P2P. Need to set the Donlge's MAC address, and then use that. - */ - if (!memcmp(temp_addr, dhd->iflist[0]->mac_addr, - ETHER_ADDR_LEN)) { - DHD_ERROR(("%s interface [%s]: set locally administered bit in MAC\n", - __func__, net->name)); - temp_addr[0] |= 0x02; - } - } - - net->hard_header_len = ETH_HLEN + dhd->pub.hdrlen; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) - net->ethtool_ops = &dhd_ethtool_ops; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) */ - -#if defined(CONFIG_WIRELESS_EXT) -#if WIRELESS_EXT < 19 - net->get_wireless_stats = dhd_get_wireless_stats; -#endif /* WIRELESS_EXT < 19 */ -#if WIRELESS_EXT > 12 - net->wireless_handlers = (struct iw_handler_def *)&wl_iw_handler_def; -#endif /* WIRELESS_EXT > 12 */ -#endif /* defined(CONFIG_WIRELESS_EXT) */ - - dhd->pub.rxsz = DBUS_RX_BUFFER_SIZE_DHD(net); - - memcpy(net->dev_addr, temp_addr, ETHER_ADDR_LEN); - - if ((err = register_netdev(net)) != 0) { - DHD_ERROR(("couldn't register the net device, err %d\n", err)); - goto fail; - } - printf("Broadcom Dongle Host Driver: register interface [%s]", - net->name); - -#if defined(SOFTAP) && defined(CONFIG_WIRELESS_EXT) && !defined(WL_CFG80211) - wl_iw_iscan_set_scan_broadcast_prep(net, 1); -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - if (ifidx == 0) { - dhd_registration_check = TRUE; - up(&dhd_registration_sem); - } -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ - return 0; - -fail: -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31) - net->open = NULL; -#else - net->netdev_ops = NULL; -#endif - return err; -} - -void -dhd_bus_detach(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhdp) { - dhd = (dhd_info_t *)dhdp->info; - if (dhd) { - - /* - * In case of Android cfg80211 driver, the bus is down in dhd_stop, - * calling stop again will cuase SD read/write errors. - */ - if (dhd->pub.busstate != DHD_BUS_DOWN) { - /* Stop the protocol module */ - dhd_prot_stop(&dhd->pub); - - /* Stop the bus module */ - dhd_bus_stop(dhd->pub.bus, TRUE); - } - -#if defined(OOB_INTR_ONLY) - bcmsdh_unregister_oob_intr(); -#endif /* defined(OOB_INTR_ONLY) */ - } - } -} - - -void dhd_detach(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - unsigned long flags; - int timer_valid = FALSE; - - if (!dhdp) - return; - - dhd = (dhd_info_t *)dhdp->info; - if (!dhd) - return; - - DHD_TRACE(("%s: Enter state 0x%x\n", __FUNCTION__, dhd->dhd_state)); - -#ifdef CUSTOMER_HW_SAMSUNG - /* - * CSP #506108 - * kernel panic issue when first bootup time, - * rmmod without interface down make unnecessary hang event. - */ - dhd->pub.up = 0; -#endif - - if (!(dhd->dhd_state & DHD_ATTACH_STATE_DONE)) { - /* Give sufficient time for threads to start running in case - * dhd_attach() has failed - */ - osl_delay(1000*100); - } -#ifdef CUSTOMER_HW_SAMSUNG - /* CSP#482857: Change the location of dhd_bus_detach() - * to avoid Kernel panic problem - */ - if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { - dhd_bus_detach(dhdp); - - if (dhdp->prot) - dhd_prot_detach(dhdp); - } -#endif /* CUSTOMER_HW_SAMSUNG */ - -#ifdef ARP_OFFLOAD_SUPPORT - unregister_inetaddr_notifier(&dhd_notifier); -#endif /* ARP_OFFLOAD_SUPPORT */ - -#if defined(CONFIG_HAS_EARLYSUSPEND) - if (dhd->dhd_state & DHD_ATTACH_STATE_EARLYSUSPEND_DONE) { - if (dhd->early_suspend.suspend) - unregister_early_suspend(&dhd->early_suspend); - } -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ - - -#if defined(CONFIG_WIRELESS_EXT) - if (dhd->dhd_state & DHD_ATTACH_STATE_WL_ATTACH) { - /* Detatch and unlink in the iw */ - wl_iw_detach(); - } -#endif /* defined(CONFIG_WIRELESS_EXT) */ - - if (dhd->thr_sysioc_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_sysioc_ctl); - } - - /* delete all interfaces, start with virtual */ - if (dhd->dhd_state & DHD_ATTACH_STATE_ADD_IF) { - int i = 1; - dhd_if_t *ifp; - - /* Cleanup virtual interfaces */ - for (i = 1; i < DHD_MAX_IFS; i++) - if (dhd->iflist[i]) { - dhd->iflist[i]->state = DHD_IF_DEL; - dhd->iflist[i]->idx = i; - dhd_op_if(dhd->iflist[i]); - } - - /* delete primary interface 0 */ - ifp = dhd->iflist[0]; - ASSERT(ifp); - ASSERT(ifp->net); - if (ifp && ifp->net) - { - -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)) - if (ifp->net->open) -#else - if (ifp->net->netdev_ops == &dhd_ops_pri) -#endif - { - unregister_netdev(ifp->net); - free_netdev(ifp->net); - ifp->net = NULL; - MFREE(dhd->pub.osh, ifp, sizeof(*ifp)); - dhd->iflist[0] = NULL; - } - } - } - - /* Clear the watchdog timer */ - flags = dhd_os_spin_lock(&dhd->pub); - timer_valid = dhd->wd_timer_valid; - dhd->wd_timer_valid = FALSE; - dhd_os_spin_unlock(&dhd->pub, flags); - if (timer_valid) - del_timer_sync(&dhd->timer); - - if (dhd->dhd_state & DHD_ATTACH_STATE_THREADS_CREATED) { -#ifdef DHDTHREAD - if (dhd->thr_wdt_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_wdt_ctl); - } - - if (dhd->thr_dpc_ctl.thr_pid >= 0) { - PROC_STOP(&dhd->thr_dpc_ctl); - } - else -#endif /* DHDTHREAD */ - tasklet_kill(&dhd->tasklet); - } -#ifndef CUSTOMER_HW_SAMSUNG - if (dhd->dhd_state & DHD_ATTACH_STATE_PROT_ATTACH) { - dhd_bus_detach(dhdp); - - if (dhdp->prot) - dhd_prot_detach(dhdp); - } -#endif /* CUSTOMER_HW_SAMSUNG */ - -#ifdef WL_CFG80211 - if (dhd->dhd_state & DHD_ATTACH_STATE_CFG80211) { - wl_cfg80211_detach(NULL); - dhd_monitor_uninit(); - } -#endif - - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) - unregister_pm_notifier(&dhd_sleep_pm_notifier); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) && defined(CONFIG_PM_SLEEP) */ - /* && defined(CONFIG_PM_SLEEP) */ - - if (dhd->dhd_state & DHD_ATTACH_STATE_WAKELOCKS_INIT) { -#ifdef CONFIG_HAS_WAKELOCK - dhd->wakelock_counter = 0; - dhd->wakelock_timeout_enable = 0; - wake_lock_destroy(&dhd->wl_wifi); - wake_lock_destroy(&dhd->wl_rxwake); -#ifdef PNO_SUPPORT - wake_lock_destroy(&dhdp->pno_wakelock); -#endif -#endif - } -} - - -void -dhd_free(dhd_pub_t *dhdp) -{ - dhd_info_t *dhd; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (dhdp) { - int i; - for (i = 0; i < ARRAYSIZE(dhdp->reorder_bufs); i++) { - if (dhdp->reorder_bufs[i]) { - reorder_info_t *ptr; - uint32 buf_size = sizeof(struct reorder_info); - - ptr = dhdp->reorder_bufs[i]; - - buf_size += ((ptr->max_idx + 1) * sizeof(void*)); - DHD_REORDER(("free flow id buf %d, maxidx is %d, buf_size %d\n", - i, ptr->max_idx, buf_size)); - - MFREE(dhdp->osh, dhdp->reorder_bufs[i], buf_size); - dhdp->reorder_bufs[i] = NULL; - } - } - dhd = (dhd_info_t *)dhdp->info; - if (dhd) - MFREE(dhd->pub.osh, dhd, sizeof(*dhd)); - } -} - -static void __exit -dhd_module_cleanup(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - dhd_bus_unregister(); - -#if defined(CONFIG_WIFI_CONTROL_FUNC) - wl_android_wifictrl_func_del(); -#endif /* CONFIG_WIFI_CONTROL_FUNC */ - wl_android_exit(); - - /* Call customer gpio to turn off power with WL_REG_ON signal */ - dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); -} - - -static int __init -dhd_module_init(void) -{ - int error = 0; - -#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - int retry = POWERUP_MAX_RETRY; - int chip_up = 0; -#endif - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - wl_android_init(); - -#if defined(DHDTHREAD) - /* Sanity check on the module parameters */ - do { - /* Both watchdog and DPC as tasklets are ok */ - if ((dhd_watchdog_prio < 0) && (dhd_dpc_prio < 0)) - break; - - /* If both watchdog and DPC are threads, TX must be deferred */ - if ((dhd_watchdog_prio >= 0) && (dhd_dpc_prio >= 0) && dhd_deferred_tx) - break; - - DHD_ERROR(("Invalid module parameters.\n")); - return -EINVAL; - } while (0); -#endif - -#if 1 && defined(BCMLXSDMMC) && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - do { - sema_init(&dhd_chipup_sem, 0); - dhd_bus_reg_sdio_notify(&dhd_chipup_sem); - dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); -#if defined(CONFIG_WIFI_CONTROL_FUNC) - if (wl_android_wifictrl_func_add() < 0) { - dhd_bus_unreg_sdio_notify(); - goto fail_1; - } -#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ - if (down_timeout(&dhd_chipup_sem, - msecs_to_jiffies(POWERUP_WAIT_MS)) == 0) { - dhd_bus_unreg_sdio_notify(); - chip_up = 1; - break; - } - DHD_ERROR(("\nfailed to power up wifi chip, retry again (%d left) **\n\n", - retry+1)); - dhd_bus_unreg_sdio_notify(); -#if defined(CONFIG_WIFI_CONTROL_FUNC) - wl_android_wifictrl_func_del(); -#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ - dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); - } while (retry-- > 0); - - if (!chip_up) { - DHD_ERROR(("\nfailed to power up wifi chip, max retry reached, exits **\n\n")); - return -ENODEV; - } -#else - dhd_customer_gpio_wlan_ctrl(WLAN_POWER_ON); -#if defined(CONFIG_WIFI_CONTROL_FUNC) - if (wl_android_wifictrl_func_add() < 0) - goto fail_1; -#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ -#endif /* BCMLXSDMMC */ - -#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - sema_init(&dhd_registration_sem, 0); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ - error = dhd_bus_register(); - - if (!error) - DHD_TRACE(("%s: \n%s\n", __FUNCTION__, dhd_version)); - else { - DHD_ERROR(("%s: sdio_register_driver failed\n", __FUNCTION__)); - goto fail_1; - } - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - /* - * Wait till MMC sdio_register_driver callback called and made driver attach. - * It's needed to make sync up exit from dhd insmod and - * Kernel MMC sdio device callback registration - */ - if (down_timeout(&dhd_registration_sem, msecs_to_jiffies(DHD_REGISTRATION_TIMEOUT)) != 0) { - error = -ENODEV; - DHD_ERROR(("%s: sdio_register_driver timeout\n", __FUNCTION__)); - goto fail_2; - } - if (dhd_registration_check != TRUE) - { - error = -ENODEV; - DHD_ERROR(("%s: sdio_register_driver fail\n", __FUNCTION__)); - goto fail_2; - } -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ -#if defined(WL_CFG80211) - wl_android_post_init(); -#endif /* defined(WL_CFG80211) */ - - return error; - -#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) -fail_2: - dhd_bus_unregister(); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ - -fail_1: - -#if defined(CONFIG_WIFI_CONTROL_FUNC) - wl_android_wifictrl_func_del(); -#endif - - /* Call customer gpio to turn off power with WL_REG_ON signal */ - dhd_customer_gpio_wlan_ctrl(WLAN_POWER_OFF); - - return error; -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) -late_initcall(dhd_module_init); -#else -module_init(dhd_module_init); -#endif - -module_exit(dhd_module_cleanup); - -/* - * OS specific functions required to implement DHD driver in OS independent way - */ -int -dhd_os_proto_block(dhd_pub_t *pub) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - down(&dhd->proto_sem); - return 1; - } - - return 0; -} - -int -dhd_os_proto_unblock(dhd_pub_t *pub) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - - if (dhd) { - up(&dhd->proto_sem); - return 1; - } - - return 0; -} - -unsigned int -dhd_os_get_ioctl_resp_timeout(void) -{ - return ((unsigned int)dhd_ioctl_timeout_msec); -} - -void -dhd_os_set_ioctl_resp_timeout(unsigned int timeout_msec) -{ - dhd_ioctl_timeout_msec = (int)timeout_msec; -} - -int -dhd_os_ioctl_resp_wait(dhd_pub_t *pub, uint *condition, bool *pending) -{ - dhd_info_t * dhd = (dhd_info_t *)(pub->info); - DECLARE_WAITQUEUE(wait, current); - int timeout = dhd_ioctl_timeout_msec; - - /* Convert timeout in millsecond to jiffies */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) - timeout = msecs_to_jiffies(timeout); -#else - timeout = timeout * HZ / 1000; -#endif - - /* Wait until control frame is available */ - add_wait_queue(&dhd->ioctl_resp_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - - /* Memory barrier to support multi-processing - * As the variable "condition", which points to dhd->rxlen (dhd_bus_rxctl[dhd_sdio.c]) - * Can be changed by another processor. - */ - smp_mb(); - while (!(*condition) && (!signal_pending(current) && timeout)) { - timeout = schedule_timeout(timeout); - smp_mb(); - } - - if (signal_pending(current)) - *pending = TRUE; - - set_current_state(TASK_RUNNING); - remove_wait_queue(&dhd->ioctl_resp_wait, &wait); - - return timeout; -} - -int -dhd_os_ioctl_resp_wake(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (waitqueue_active(&dhd->ioctl_resp_wait)) { - wake_up_interruptible(&dhd->ioctl_resp_wait); - } - - return 0; -} - -void -dhd_os_wd_timer(void *bus, uint wdtick) -{ - dhd_pub_t *pub = bus; - dhd_info_t *dhd = (dhd_info_t *)pub->info; - unsigned long flags; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!dhd) - return; - - flags = dhd_os_spin_lock(pub); - - /* don't start the wd until fw is loaded */ - if (pub->busstate == DHD_BUS_DOWN) { - dhd_os_spin_unlock(pub, flags); - return; - } - - /* Totally stop the timer */ - if (!wdtick && dhd->wd_timer_valid == TRUE) { - dhd->wd_timer_valid = FALSE; - dhd_os_spin_unlock(pub, flags); - if (dhd) -#ifdef DHDTHREAD - del_timer_sync(&dhd->timer); -#else - del_timer(&dhd->timer); -#endif /* DHDTHREAD */ - return; - } - - if (wdtick) { - dhd_watchdog_ms = (uint)wdtick; - /* Re arm the timer, at last watchdog period */ - mod_timer(&dhd->timer, jiffies + dhd_watchdog_ms * HZ / 1000); - dhd->wd_timer_valid = TRUE; - } - dhd_os_spin_unlock(pub, flags); -} - -void * -dhd_os_open_image(char *filename) -{ - struct file *fp; - - fp = filp_open(filename, O_RDONLY, 0); - /* - * 2.6.11 (FC4) supports filp_open() but later revs don't? - * Alternative: - * fp = open_namei(AT_FDCWD, filename, O_RD, 0); - * ??? - */ - if (IS_ERR(fp)) - fp = NULL; - - return fp; -} - -int -dhd_os_get_image_block(char *buf, int len, void *image) -{ - struct file *fp = (struct file *)image; - int rdlen; - - if (!image) - return 0; - - rdlen = kernel_read(fp, fp->f_pos, buf, len); - if (rdlen > 0) - fp->f_pos += rdlen; - - return rdlen; -} - -void -dhd_os_close_image(void *image) -{ - if (image) - filp_close((struct file *)image, NULL); -} - - -void -dhd_os_sdlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - -#ifdef DHDTHREAD - if (dhd->threads_only) - down(&dhd->sdsem); - else -#endif /* DHDTHREAD */ - spin_lock_bh(&dhd->sdlock); -} - -void -dhd_os_sdunlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - -#ifdef DHDTHREAD - if (dhd->threads_only) - up(&dhd->sdsem); - else -#endif /* DHDTHREAD */ - spin_unlock_bh(&dhd->sdlock); -} - -void -dhd_os_sdlock_txq(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_lock_bh(&dhd->txqlock); -} - -void -dhd_os_sdunlock_txq(dhd_pub_t *pub) -{ - dhd_info_t *dhd; - - dhd = (dhd_info_t *)(pub->info); - spin_unlock_bh(&dhd->txqlock); -} - -void -dhd_os_sdlock_rxq(dhd_pub_t *pub) -{ -} - -void -dhd_os_sdunlock_rxq(dhd_pub_t *pub) -{ -} - -void -dhd_os_sdtxlock(dhd_pub_t *pub) -{ - dhd_os_sdlock(pub); -} - -void -dhd_os_sdtxunlock(dhd_pub_t *pub) -{ - dhd_os_sdunlock(pub); -} - -#if defined(CONFIG_DHD_USE_STATIC_BUF) -uint8* dhd_os_prealloc(void *osh, int section, uint size) -{ - return (uint8*)wl_android_prealloc(section, size); -} - -void dhd_os_prefree(void *osh, void *addr, uint size) -{ -} -#endif /* defined(CONFIG_WIFI_CONTROL_FUNC) */ - -#if defined(CONFIG_WIRELESS_EXT) -struct iw_statistics * -dhd_get_wireless_stats(struct net_device *dev) -{ - int res = 0; - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - if (!dhd->pub.up) { - return NULL; - } - - res = wl_iw_get_wireless_stats(dev, &dhd->iw.wstats); - - if (res == 0) - return &dhd->iw.wstats; - else - return NULL; -} -#endif /* defined(CONFIG_WIRELESS_EXT) */ - -static int -dhd_wl_host_event(dhd_info_t *dhd, int *ifidx, void *pktdata, - wl_event_msg_t *event, void **data) -{ - int bcmerror = 0; - ASSERT(dhd != NULL); - - bcmerror = wl_host_event(&dhd->pub, ifidx, pktdata, event, data); - if (bcmerror != BCME_OK) - return (bcmerror); - -#if defined(CONFIG_WIRELESS_EXT) - if (event->bsscfgidx == 0) { - /* - * Wireless ext is on primary interface only - */ - - ASSERT(dhd->iflist[*ifidx] != NULL); - ASSERT(dhd->iflist[*ifidx]->net != NULL); - - if (dhd->iflist[*ifidx]->net) { - wl_iw_event(dhd->iflist[*ifidx]->net, event, *data); - } - } -#endif /* defined(CONFIG_WIRELESS_EXT) */ - -#ifdef WL_CFG80211 - if ((ntoh32(event->event_type) == WLC_E_IF) && - (((dhd_if_event_t *)*data)->action == WLC_E_IF_ADD)) - /* If ADD_IF has been called directly by wl utility then we - * should not report this. In case if ADD_IF was called from - * CFG stack, then too this event need not be reported back - */ - return (BCME_OK); - if ((wl_cfg80211_is_progress_ifchange() || - wl_cfg80211_is_progress_ifadd()) && (*ifidx != 0)) { - /* - * If IF_ADD/CHANGE operation is going on, - * discard any event received on the virtual I/F - */ - return (BCME_OK); - } - - ASSERT(dhd->iflist[*ifidx] != NULL); - ASSERT(dhd->iflist[*ifidx]->net != NULL); - if (dhd->iflist[*ifidx]->event2cfg80211 && dhd->iflist[*ifidx]->net) { - wl_cfg80211_event(dhd->iflist[*ifidx]->net, event, *data); - } -#endif /* defined(WL_CFG80211) */ - - return (bcmerror); -} - -/* send up locally generated event */ -void -dhd_sendup_event(dhd_pub_t *dhdp, wl_event_msg_t *event, void *data) -{ - switch (ntoh32(event->event_type)) { -#ifdef WLBTAMP - /* Send up locally generated AMP HCI Events */ - case WLC_E_BTA_HCI_EVENT: { - struct sk_buff *p, *skb; - bcm_event_t *msg; - wl_event_msg_t *p_bcm_event; - char *ptr; - uint32 len; - uint32 pktlen; - dhd_if_t *ifp; - dhd_info_t *dhd; - uchar *eth; - int ifidx; - - len = ntoh32(event->datalen); - pktlen = sizeof(bcm_event_t) + len + 2; - dhd = dhdp->info; - ifidx = dhd_ifname2idx(dhd, event->ifname); - - if ((p = PKTGET(dhdp->osh, pktlen, FALSE))) { - ASSERT(ISALIGNED((uintptr)PKTDATA(dhdp->osh, p), sizeof(uint32))); - - msg = (bcm_event_t *) PKTDATA(dhdp->osh, p); - - bcopy(&dhdp->mac, &msg->eth.ether_dhost, ETHER_ADDR_LEN); - bcopy(&dhdp->mac, &msg->eth.ether_shost, ETHER_ADDR_LEN); - ETHER_TOGGLE_LOCALADDR(&msg->eth.ether_shost); - - msg->eth.ether_type = hton16(ETHER_TYPE_BRCM); - - /* BCM Vendor specific header... */ - msg->bcm_hdr.subtype = hton16(BCMILCP_SUBTYPE_VENDOR_LONG); - msg->bcm_hdr.version = BCMILCP_BCM_SUBTYPEHDR_VERSION; - bcopy(BRCM_OUI, &msg->bcm_hdr.oui[0], DOT11_OUI_LEN); - - /* vendor spec header length + pvt data length (private indication - * hdr + actual message itself) - */ - msg->bcm_hdr.length = hton16(BCMILCP_BCM_SUBTYPEHDR_MINLENGTH + - BCM_MSG_LEN + sizeof(wl_event_msg_t) + (uint16)len); - msg->bcm_hdr.usr_subtype = hton16(BCMILCP_BCM_SUBTYPE_EVENT); - - PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2)); - - /* copy wl_event_msg_t into sk_buf */ - - /* pointer to wl_event_msg_t in sk_buf */ - p_bcm_event = &msg->event; - bcopy(event, p_bcm_event, sizeof(wl_event_msg_t)); - - /* copy hci event into sk_buf */ - bcopy(data, (p_bcm_event + 1), len); - - msg->bcm_hdr.length = hton16(sizeof(wl_event_msg_t) + - ntoh16(msg->bcm_hdr.length)); - PKTSETLEN(dhdp->osh, p, (sizeof(bcm_event_t) + len + 2)); - - ptr = (char *)(msg + 1); - /* Last 2 bytes of the message are 0x00 0x00 to signal that there - * are no ethertypes which are following this - */ - ptr[len+0] = 0x00; - ptr[len+1] = 0x00; - - skb = PKTTONATIVE(dhdp->osh, p); - eth = skb->data; - len = skb->len; - - ifp = dhd->iflist[ifidx]; - if (ifp == NULL) - ifp = dhd->iflist[0]; - - ASSERT(ifp); - skb->dev = ifp->net; - skb->protocol = eth_type_trans(skb, skb->dev); - - skb->data = eth; - skb->len = len; - - /* Strip header, count, deliver upward */ - skb_pull(skb, ETH_HLEN); - - /* Send the packet */ - if (in_interrupt()) { - netif_rx(skb); - } else { - netif_rx_ni(skb); - } - } - else { - /* Could not allocate a sk_buf */ - DHD_ERROR(("%s: unable to alloc sk_buf", __FUNCTION__)); -} - break; - } /* case WLC_E_BTA_HCI_EVENT */ -#endif /* WLBTAMP */ - - default: - break; - } -} - -void dhd_wait_for_event(dhd_pub_t *dhd, bool *lockvar) -{ -#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - struct dhd_info *dhdinfo = dhd->info; - dhd_os_sdunlock(dhd); - wait_event_interruptible_timeout(dhdinfo->ctrl_wait, (*lockvar == FALSE), HZ * 5); - dhd_os_sdlock(dhd); -#endif - return; -} - -void dhd_wait_event_wakeup(dhd_pub_t *dhd) -{ -#if 1 && (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - struct dhd_info *dhdinfo = dhd->info; - if (waitqueue_active(&dhdinfo->ctrl_wait)) - wake_up_interruptible(&dhdinfo->ctrl_wait); -#endif - return; -} - -int -dhd_dev_reset(struct net_device *dev, uint8 flag) -{ - int ret; - - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - ret = dhd_bus_devreset(&dhd->pub, flag); - if (ret) { - DHD_ERROR(("%s: dhd_bus_devreset: %d\n", __FUNCTION__, ret)); - return ret; - } - - return ret; -} - -int net_os_set_suspend_disable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) { - ret = dhd->pub.suspend_disable_flag; - dhd->pub.suspend_disable_flag = val; - } - return ret; -} - -int net_os_set_suspend(struct net_device *dev, int val) -{ - int ret = 0; -#if defined(CONFIG_HAS_EARLYSUSPEND) - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - if (dhd) { - ret = dhd_set_suspend(val, &dhd->pub); - } -#endif /* defined(CONFIG_HAS_EARLYSUSPEND) */ - return ret; -} - -int net_os_set_dtim_skip(struct net_device *dev, int val) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - if (dhd) - dhd->pub.dtim_skip = val; - - return 0; -} - -int net_os_rxfilter_add_remove(struct net_device *dev, int add_remove, int num) -{ - return 0; -} - -int net_os_set_packet_filter(struct net_device *dev, int val) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - /* Packet filtering is set only if we still in early-suspend and - * we need either to turn it ON or turn it OFF - * We can always turn it OFF in case of early-suspend, but we turn it - * back ON only if suspend_disable_flag was not set - */ - if (dhd && dhd->pub.up) { - if (dhd->pub.in_suspend) { - if (!val || (val && !dhd->pub.suspend_disable_flag)) { - int i; - for (i = 0; i < dhd->pub.pktfilter_count; i++) - dhd_pktfilter_offload_enable(&dhd->pub, dhd->pub.pktfilter[i], - val, dhd_master_mode); - } - } - } - return ret; -} - - -void -dhd_dev_init_ioctl(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - /* Writing STA's MAC ID to the Dongle for SOFTAP */ - if (_dhd_set_mac_address(dhd, 0, &dhd->pub.mac) == 0) - DHD_INFO(("dhd_bus_start: MAC ID is overwritten\n")); - - dhd_preinit_ioctls(&dhd->pub); -} - -#ifdef PNO_SUPPORT -/* Linux wrapper to call common dhd_pno_clean */ -int -dhd_dev_pno_reset(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_clean(&dhd->pub)); -} - - -/* Linux wrapper to call common dhd_pno_enable */ -int -dhd_dev_pno_enable(struct net_device *dev, int pfn_enabled) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_enable(&dhd->pub, pfn_enabled)); -} - - -/* Linux wrapper to call common dhd_pno_set */ -int -dhd_dev_pno_set(struct net_device *dev, wlc_ssid_t* ssids_local, int nssid, - ushort scan_fr, int pno_repeat, int pno_freq_expo_max) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_set(&dhd->pub, ssids_local, nssid, scan_fr, pno_repeat, pno_freq_expo_max)); -} - -/* Linux wrapper to get pno status */ -int -dhd_dev_get_pno_status(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - return (dhd_pno_get_status(&dhd->pub)); -} - -#endif /* PNO_SUPPORT */ - -int net_os_send_hang_message(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) { - if (!dhd->pub.hang_was_sent) { - dhd->pub.hang_was_sent = 1; -#if defined(CONFIG_WIRELESS_EXT) - ret = wl_iw_send_priv_event(dev, "HANG"); -#endif -#if defined(WL_CFG80211) - ret = wl_cfg80211_hang(dev, WLAN_REASON_UNSPECIFIED); -#if !defined(CUSTOMER_HW_SAMSUNG) -#error do not use these it cause kernel panic - dev_close(dev); - dev_open(dev); -#endif -#endif /* WL_CFG80211 */ - } - } - return ret; -} - -void dhd_bus_country_set(struct net_device *dev, wl_country_t *cspec) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - - if (dhd && dhd->pub.up) - memcpy(&dhd->pub.dhd_cspec, cspec, sizeof(wl_country_t)); -} - -void dhd_net_if_lock(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - dhd_net_if_lock_local(dhd); -} - -void dhd_net_if_unlock(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - dhd_net_if_unlock_local(dhd); -} - -static void dhd_net_if_lock_local(dhd_info_t *dhd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - if (dhd) - mutex_lock(&dhd->dhd_net_if_mutex); -#endif -} - -static void dhd_net_if_unlock_local(dhd_info_t *dhd) -{ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) && 1 - if (dhd) - mutex_unlock(&dhd->dhd_net_if_mutex); -#endif -} - -unsigned long dhd_os_spin_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags = 0; - - if (dhd) - spin_lock_irqsave(&dhd->dhd_lock, flags); - - return flags; -} - -void dhd_os_spin_unlock(dhd_pub_t *pub, unsigned long flags) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - - if (dhd) - spin_unlock_irqrestore(&dhd->dhd_lock, flags); -} - -static int -dhd_get_pend_8021x_cnt(dhd_info_t *dhd) -{ - return (atomic_read(&dhd->pend_8021x_cnt)); -} - -#define MAX_WAIT_FOR_8021X_TX 10 - -int -dhd_wait_pend8021x(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int timeout = 10 * HZ / 1000; - int ntimes = MAX_WAIT_FOR_8021X_TX; - int pend = dhd_get_pend_8021x_cnt(dhd); - - while (ntimes && pend) { - if (pend) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(timeout); - set_current_state(TASK_RUNNING); - ntimes--; - } - pend = dhd_get_pend_8021x_cnt(dhd); - } - return pend; -} - -#ifdef DHD_DEBUG -int -write_to_file(dhd_pub_t *dhd, uint8 *buf, int size) -{ - int ret = 0; - struct file *fp; - mm_segment_t old_fs; - loff_t pos = 0; - - /* change to KERNEL_DS address limit */ - old_fs = get_fs(); - set_fs(KERNEL_DS); - - /* open file to write */ - fp = filp_open("/tmp/mem_dump", O_WRONLY|O_CREAT, 0640); - if (!fp) { - printf("%s: open file error\n", __FUNCTION__); - ret = -1; - goto exit; - } - - /* Write buf to file */ - fp->f_op->write(fp, buf, size, &pos); - -exit: - /* free buf before return */ - MFREE(dhd->osh, buf, size); - /* close file before return */ - if (fp) - filp_close(fp, current->files); - /* restore previous address limit */ - set_fs(old_fs); - - return ret; -} -#endif /* DHD_DEBUG */ - -int dhd_os_wake_lock_timeout(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - ret = dhd->wakelock_timeout_enable; -#ifdef CONFIG_HAS_WAKELOCK - if (dhd->wakelock_timeout_enable) - wake_lock_timeout(&dhd->wl_rxwake, - msecs_to_jiffies(dhd->wakelock_timeout_enable)); -#endif - dhd->wakelock_timeout_enable = 0; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int net_os_wake_lock_timeout(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock_timeout(&dhd->pub); - return ret; -} -#if defined(PNO_SUPPORT) && defined(CONFIG_HAS_WAKELOCK) -int net_os_wake_lock_timeout_for_pno(struct net_device *dev, int sec) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - unsigned long flags; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - wake_lock_timeout(&dhd->pub.pno_wakelock, HZ * sec); - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} -#endif - -int dhd_os_wake_lock_timeout_enable(dhd_pub_t *pub, int val) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (val > dhd->wakelock_timeout_enable) - dhd->wakelock_timeout_enable = val; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return 0; -} - -int net_os_wake_lock_timeout_enable(struct net_device *dev, int val) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock_timeout_enable(&dhd->pub, val); - return ret; -} - -int dhd_os_wake_lock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); -#ifdef CONFIG_HAS_WAKELOCK - if (!dhd->wakelock_counter) - wake_lock(&dhd->wl_wifi); -#elif defined(CONFIG_PM_SLEEP) && defined(CUSTOMER_HW_SLP) - /*SLP_wakelock_alternative_code*/ - pm_stay_awake(pm_dev); -#endif - dhd->wakelock_counter++; - ret = dhd->wakelock_counter; - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int net_os_wake_lock(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_lock(&dhd->pub); - return ret; -} - -int dhd_os_wake_unlock(dhd_pub_t *pub) -{ - dhd_info_t *dhd = (dhd_info_t *)(pub->info); - unsigned long flags; - int ret = 0; - - dhd_os_wake_lock_timeout(pub); - if (dhd) { - spin_lock_irqsave(&dhd->wakelock_spinlock, flags); - if (dhd->wakelock_counter) { - dhd->wakelock_counter--; -#ifdef CONFIG_HAS_WAKELOCK - if (!dhd->wakelock_counter) - wake_unlock(&dhd->wl_wifi); -#elif defined(CONFIG_PM_SLEEP) && defined(CUSTOMER_HW_SLP) - /*SLP_wakelock_alternative_code*/ - pm_relax(pm_dev); -#endif - ret = dhd->wakelock_counter; - } - spin_unlock_irqrestore(&dhd->wakelock_spinlock, flags); - } - return ret; -} - -int dhd_os_check_wakelock(void *dhdp) -{ -#ifdef CONFIG_HAS_WAKELOCK - dhd_pub_t *pub = (dhd_pub_t *)dhdp; - dhd_info_t *dhd; - - if (!pub) - return 0; - dhd = (dhd_info_t *)(pub->info); - - if (dhd && wake_lock_active(&dhd->wl_wifi)) - return 1; -#elif defined(CONFIG_PM_SLEEP) && defined(CUSTOMER_HW_SLP) - /*SLP_wakelock_alternative_code*/ - dhd_pub_t *pub = (dhd_pub_t *)dhdp; - dhd_info_t *dhd; - - if (!pub) - return 0; - dhd = (dhd_info_t *)(pub->info); - - DHD_ERROR(("%s : wakelock_count = %d\n", __func__, dhd->wakelock_counter )); - - if (dhd && (dhd->wakelock_counter > 0)) - return 1; -#endif - return 0; -} -int net_os_wake_unlock(struct net_device *dev) -{ - dhd_info_t *dhd = *(dhd_info_t **)netdev_priv(dev); - int ret = 0; - - if (dhd) - ret = dhd_os_wake_unlock(&dhd->pub); - return ret; -} - -int dhd_os_check_if_up(void *dhdp) -{ - dhd_pub_t *pub = (dhd_pub_t *)dhdp; - - if (!pub) - return 0; - return pub->up; -} -int dhd_ioctl_entry_local(struct net_device *net, wl_ioctl_t *ioc, int cmd) -{ - int ifidx; - int ret = 0; - dhd_info_t *dhd = NULL; - - if (!net || !netdev_priv(net)) { - DHD_ERROR(("%s invalid parameter\n", __FUNCTION__)); - return -EINVAL; - } - - dhd = *(dhd_info_t **)netdev_priv(net); - ifidx = dhd_net2idx(dhd, net); - if (ifidx == DHD_BAD_IF) { - DHD_ERROR(("%s bad ifidx\n", __FUNCTION__)); - return -ENODEV; - } - - DHD_OS_WAKE_LOCK(&dhd->pub); - ret = dhd_wl_ioctl(&dhd->pub, ifidx, ioc, ioc->buf, ioc->len); - dhd_check_hang(net, &dhd->pub, ret); - DHD_OS_WAKE_UNLOCK(&dhd->pub); - - return ret; -} - -bool dhd_os_check_hang(dhd_pub_t *dhdp, int ifidx, int ret) -{ - struct net_device *net; - - net = dhd_idx2net(dhdp, ifidx); - return dhd_check_hang(net, dhdp, ret); -} - -#if defined(WL_CFG80211) && defined(CUSTOMER_HW_SAMSUNG) -#define MAX_TRY_CNT 5 /* Number of tries to disable deepsleep */ -int dhd_deepsleep(struct net_device *dev, int flag) -{ - char iovbuf[20]; - uint powervar = 0; - dhd_info_t *dhd; - dhd_pub_t *dhdp; - int cnt = 0; - int ret = 0; - - dhd = *(dhd_info_t **)netdev_priv(dev); - dhdp = &dhd->pub; - - switch (flag) { - case 1 : /* Deepsleep on */ - DHD_ERROR(("[WiFi] Deepsleep On\n")); - /* give some time to _dhd_sysioc_thread() before deepsleep */ - msleep(200); - if (dhd_pkt_filter_enable) { - dhd_set_packet_filter(0, dhdp); - } - /* Disable MPC */ - powervar = 0; - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - - /* Enable Deepsleep*/ - powervar = 1; - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("deepsleep", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - break; - - case 0: /* Deepsleep Off */ - DHD_ERROR(("[WiFi] Deepsleep Off\n")); - - /* Disable Deepsleep */ - for (cnt = 0; cnt < MAX_TRY_CNT; cnt++ ) { - powervar = 0; - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("deepsleep", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("deepsleep", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); - if ((ret = dhd_wl_ioctl_cmd(dhdp, WLC_GET_VAR, iovbuf, sizeof(iovbuf), FALSE, 0)) < 0) { - DHD_ERROR(("the error of dhd deepsleep status ret value : %d\n",ret)); - } else { - if(!(*(int *)iovbuf )) { - DHD_ERROR(("deepsleep mode is 0, ok , count : %d\n",cnt)); - break; - } - } - } - - /* Enable MPC */ - powervar = 1; - memset(iovbuf, 0, sizeof(iovbuf)); - bcm_mkiovar("mpc", (char *)&powervar, 4, iovbuf, sizeof(iovbuf)); - dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0); - break; - } - - return 0; -} -#endif /* CUSTOMER_HW_SAMSUNG */ - -#ifdef PROP_TXSTATUS -extern int dhd_wlfc_interface_entry_update(void* state, ewlfc_mac_entry_action_t action, uint8 ifid, - uint8 iftype, uint8* ea); -extern int dhd_wlfc_FIFOcreditmap_update(void* state, uint8* credits); - -int dhd_wlfc_interface_event(struct dhd_info *dhd, - ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea) -{ - if (dhd->pub.wlfc_state == NULL) - return BCME_OK; - - return dhd_wlfc_interface_entry_update(dhd->pub.wlfc_state, action, ifid, iftype, ea); -} - -int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data) -{ - if (dhd->pub.wlfc_state == NULL) - return BCME_OK; - - return dhd_wlfc_FIFOcreditmap_update(dhd->pub.wlfc_state, event_data); -} - -int dhd_wlfc_event(struct dhd_info *dhd) -{ - return dhd_wlfc_enable(&dhd->pub); -} -#endif /* PROP_TXSTATUS */ - -#ifdef BCMDBGFS - -#include <linux/debugfs.h> - -extern uint32 dhd_readregl(void *bp, uint32 addr); -extern uint32 dhd_writeregl(void *bp, uint32 addr, uint32 data); - -typedef struct dhd_dbgfs { - struct dentry *debugfs_dir; - struct dentry *debugfs_mem; - dhd_pub_t *dhdp; - uint32 size; -} dhd_dbgfs_t; - -dhd_dbgfs_t g_dbgfs; - -static int -dhd_dbg_state_open(struct inode *inode, struct file *file) -{ - file->private_data = inode->i_private; - return 0; -} - -static ssize_t -dhd_dbg_state_read(struct file *file, char __user *ubuf, - size_t count, loff_t *ppos) -{ - ssize_t rval; - uint32 tmp; - loff_t pos = *ppos; - size_t ret; - - if (pos < 0) - return -EINVAL; - if (pos >= g_dbgfs.size || !count) - return 0; - if (count > g_dbgfs.size - pos) - count = g_dbgfs.size - pos; - - /* Basically enforce aligned 4 byte reads. It's up to the user to work out the details */ - tmp = dhd_readregl(g_dbgfs.dhdp->bus, file->f_pos & (~3)); - - ret = copy_to_user(ubuf, &tmp, 4); - if (ret == count) - return -EFAULT; - - count -= ret; - *ppos = pos + count; - rval = count; - - return rval; -} - - -static ssize_t -dhd_debugfs_write(struct file *file, const char __user *ubuf, size_t count, loff_t *ppos) -{ - loff_t pos = *ppos; - size_t ret; - uint32 buf; - - if (pos < 0) - return -EINVAL; - if (pos >= g_dbgfs.size || !count) - return 0; - if (count > g_dbgfs.size - pos) - count = g_dbgfs.size - pos; - - ret = copy_from_user(&buf, ubuf, sizeof(uint32)); - if (ret == count) - return -EFAULT; - - /* Basically enforce aligned 4 byte writes. It's up to the user to work out the details */ - dhd_writeregl(g_dbgfs.dhdp->bus, file->f_pos & (~3), buf); - - return count; -} - - -loff_t -dhd_debugfs_lseek(struct file *file, loff_t off, int whence) -{ - loff_t pos = -1; - - switch (whence) { - case 0: - pos = off; - break; - case 1: - pos = file->f_pos + off; - break; - case 2: - pos = g_dbgfs.size - off; - } - return (pos < 0 || pos > g_dbgfs.size) ? -EINVAL : (file->f_pos = pos); -} - -static const struct file_operations dhd_dbg_state_ops = { - .read = dhd_dbg_state_read, - .write = dhd_debugfs_write, - .open = dhd_dbg_state_open, - .llseek = dhd_debugfs_lseek -}; - -static void dhd_dbg_create(void) -{ - if (g_dbgfs.debugfs_dir) { - g_dbgfs.debugfs_mem = debugfs_create_file("mem", 0644, g_dbgfs.debugfs_dir, - NULL, &dhd_dbg_state_ops); - } -} - -void dhd_dbg_init(dhd_pub_t *dhdp) -{ - int err; - - g_dbgfs.dhdp = dhdp; - g_dbgfs.size = 0x20000000; /* Allow access to various cores regs */ - - g_dbgfs.debugfs_dir = debugfs_create_dir("dhd", 0); - if (IS_ERR(g_dbgfs.debugfs_dir)) { - err = PTR_ERR(g_dbgfs.debugfs_dir); - g_dbgfs.debugfs_dir = NULL; - return; - } - - dhd_dbg_create(); - - return; -} - -void dhd_dbg_remove(void) -{ - debugfs_remove(g_dbgfs.debugfs_mem); - debugfs_remove(g_dbgfs.debugfs_dir); - - bzero((unsigned char *) &g_dbgfs, sizeof(g_dbgfs)); - -} -#endif /* ifdef BCMDBGFS */ - -#ifdef WLMEDIA_HTSF - -static -void dhd_htsf_addtxts(dhd_pub_t *dhdp, void *pktbuf) -{ - dhd_info_t *dhd = (dhd_info_t *)(dhdp->info); - struct sk_buff *skb; - uint32 htsf = 0; - uint16 dport = 0, oldmagic = 0xACAC; - char *p1; - htsfts_t ts; - - /* timestamp packet */ - - p1 = (char*) PKTDATA(dhdp->osh, pktbuf); - - if (PKTLEN(dhdp->osh, pktbuf) > HTSF_MINLEN) { -/* memcpy(&proto, p1+26, 4); */ - memcpy(&dport, p1+40, 2); -/* proto = ((ntoh32(proto))>> 16) & 0xFF; */ - dport = ntoh16(dport); - } - - /* timestamp only if icmp or udb iperf with port 5555 */ -/* if (proto == 17 && dport == tsport) { */ - if (dport >= tsport && dport <= tsport + 20) { - - skb = (struct sk_buff *) pktbuf; - - htsf = dhd_get_htsf(dhd, 0); - memset(skb->data + 44, 0, 2); /* clear checksum */ - memcpy(skb->data+82, &oldmagic, 2); - memcpy(skb->data+84, &htsf, 4); - - memset(&ts, 0, sizeof(htsfts_t)); - ts.magic = HTSFMAGIC; - ts.prio = PKTPRIO(pktbuf); - ts.seqnum = htsf_seqnum++; - ts.c10 = get_cycles(); - ts.t10 = htsf; - ts.endmagic = HTSFENDMAGIC; - - memcpy(skb->data + HTSF_HOSTOFFSET, &ts, sizeof(ts)); - } -} - -static void dhd_dump_htsfhisto(histo_t *his, char *s) -{ - int pktcnt = 0, curval = 0, i; - for (i = 0; i < (NUMBIN-2); i++) { - curval += 500; - printf("%d ", his->bin[i]); - pktcnt += his->bin[i]; - } - printf(" max: %d TotPkt: %d neg: %d [%s]\n", his->bin[NUMBIN-2], pktcnt, - his->bin[NUMBIN-1], s); -} - -static -void sorttobin(int value, histo_t *histo) -{ - int i, binval = 0; - - if (value < 0) { - histo->bin[NUMBIN-1]++; - return; - } - if (value > histo->bin[NUMBIN-2]) /* store the max value */ - histo->bin[NUMBIN-2] = value; - - for (i = 0; i < (NUMBIN-2); i++) { - binval += 500; /* 500m s bins */ - if (value <= binval) { - histo->bin[i]++; - return; - } - } - histo->bin[NUMBIN-3]++; -} - -static -void dhd_htsf_addrxts(dhd_pub_t *dhdp, void *pktbuf) -{ - dhd_info_t *dhd = (dhd_info_t *)dhdp->info; - struct sk_buff *skb; - char *p1; - uint16 old_magic; - int d1, d2, d3, end2end; - htsfts_t *htsf_ts; - uint32 htsf; - - skb = PKTTONATIVE(dhdp->osh, pktbuf); - p1 = (char*)PKTDATA(dhdp->osh, pktbuf); - - if (PKTLEN(osh, pktbuf) > HTSF_MINLEN) { - memcpy(&old_magic, p1+78, 2); - htsf_ts = (htsfts_t*) (p1 + HTSF_HOSTOFFSET - 4); - } - else - return; - - if (htsf_ts->magic == HTSFMAGIC) { - htsf_ts->tE0 = dhd_get_htsf(dhd, 0); - htsf_ts->cE0 = get_cycles(); - } - - if (old_magic == 0xACAC) { - - tspktcnt++; - htsf = dhd_get_htsf(dhd, 0); - memcpy(skb->data+92, &htsf, sizeof(uint32)); - - memcpy(&ts[tsidx].t1, skb->data+80, 16); - - d1 = ts[tsidx].t2 - ts[tsidx].t1; - d2 = ts[tsidx].t3 - ts[tsidx].t2; - d3 = ts[tsidx].t4 - ts[tsidx].t3; - end2end = ts[tsidx].t4 - ts[tsidx].t1; - - sorttobin(d1, &vi_d1); - sorttobin(d2, &vi_d2); - sorttobin(d3, &vi_d3); - sorttobin(end2end, &vi_d4); - - if (end2end > 0 && end2end > maxdelay) { - maxdelay = end2end; - maxdelaypktno = tspktcnt; - memcpy(&maxdelayts, &ts[tsidx], 16); - } - if (++tsidx >= TSMAX) - tsidx = 0; - } -} - -uint32 dhd_get_htsf(dhd_info_t *dhd, int ifidx) -{ - uint32 htsf = 0, cur_cycle, delta, delta_us; - uint32 factor, baseval, baseval2; - cycles_t t; - - t = get_cycles(); - cur_cycle = t; - - if (cur_cycle > dhd->htsf.last_cycle) - delta = cur_cycle - dhd->htsf.last_cycle; - else { - delta = cur_cycle + (0xFFFFFFFF - dhd->htsf.last_cycle); - } - - delta = delta >> 4; - - if (dhd->htsf.coef) { - /* times ten to get the first digit */ - factor = (dhd->htsf.coef*10 + dhd->htsf.coefdec1); - baseval = (delta*10)/factor; - baseval2 = (delta*10)/(factor+1); - delta_us = (baseval - (((baseval - baseval2) * dhd->htsf.coefdec2)) / 10); - htsf = (delta_us << 4) + dhd->htsf.last_tsf + HTSF_BUS_DELAY; - } - else { - DHD_ERROR(("-------dhd->htsf.coef = 0 -------\n")); - } - - return htsf; -} - -static void dhd_dump_latency(void) -{ - int i, max = 0; - int d1, d2, d3, d4, d5; - - printf("T1 T2 T3 T4 d1 d2 t4-t1 i \n"); - for (i = 0; i < TSMAX; i++) { - d1 = ts[i].t2 - ts[i].t1; - d2 = ts[i].t3 - ts[i].t2; - d3 = ts[i].t4 - ts[i].t3; - d4 = ts[i].t4 - ts[i].t1; - d5 = ts[max].t4-ts[max].t1; - if (d4 > d5 && d4 > 0) { - max = i; - } - printf("%08X %08X %08X %08X \t%d %d %d %d i=%d\n", - ts[i].t1, ts[i].t2, ts[i].t3, ts[i].t4, - d1, d2, d3, d4, i); - } - - printf("current idx = %d \n", tsidx); - - printf("Highest latency %d pkt no.%d total=%d\n", maxdelay, maxdelaypktno, tspktcnt); - printf("%08X %08X %08X %08X \t%d %d %d %d\n", - maxdelayts.t1, maxdelayts.t2, maxdelayts.t3, maxdelayts.t4, - maxdelayts.t2 - maxdelayts.t1, - maxdelayts.t3 - maxdelayts.t2, - maxdelayts.t4 - maxdelayts.t3, - maxdelayts.t4 - maxdelayts.t1); -} - - -static int -dhd_ioctl_htsf_get(dhd_info_t *dhd, int ifidx) -{ - wl_ioctl_t ioc; - char buf[32]; - int ret; - uint32 s1, s2; - - struct tsf { - uint32 low; - uint32 high; - } tsf_buf; - - memset(&ioc, 0, sizeof(ioc)); - memset(&tsf_buf, 0, sizeof(tsf_buf)); - - ioc.cmd = WLC_GET_VAR; - ioc.buf = buf; - ioc.len = (uint)sizeof(buf); - ioc.set = FALSE; - - strcpy(buf, "tsf"); - s1 = dhd_get_htsf(dhd, 0); - if ((ret = dhd_wl_ioctl(&dhd->pub, ifidx, &ioc, ioc.buf, ioc.len)) < 0) { - if (ret == -EIO) { - DHD_ERROR(("%s: tsf is not supported by device\n", - dhd_ifname(&dhd->pub, ifidx))); - return -EOPNOTSUPP; - } - return ret; - } - s2 = dhd_get_htsf(dhd, 0); - - memcpy(&tsf_buf, buf, sizeof(tsf_buf)); - printf(" TSF_h=%04X lo=%08X Calc:htsf=%08X, coef=%d.%d%d delta=%d ", - tsf_buf.high, tsf_buf.low, s2, dhd->htsf.coef, dhd->htsf.coefdec1, - dhd->htsf.coefdec2, s2-tsf_buf.low); - printf("lasttsf=%08X lastcycle=%08X\n", dhd->htsf.last_tsf, dhd->htsf.last_cycle); - return 0; -} - -void htsf_update(dhd_info_t *dhd, void *data) -{ - static ulong cur_cycle = 0, prev_cycle = 0; - uint32 htsf, tsf_delta = 0; - uint32 hfactor = 0, cyc_delta, dec1 = 0, dec2, dec3, tmp; - ulong b, a; - cycles_t t; - - /* cycles_t in inlcude/mips/timex.h */ - - t = get_cycles(); - - prev_cycle = cur_cycle; - cur_cycle = t; - - if (cur_cycle > prev_cycle) - cyc_delta = cur_cycle - prev_cycle; - else { - b = cur_cycle; - a = prev_cycle; - cyc_delta = cur_cycle + (0xFFFFFFFF - prev_cycle); - } - - if (data == NULL) - printf(" tsf update ata point er is null \n"); - - memcpy(&prev_tsf, &cur_tsf, sizeof(tsf_t)); - memcpy(&cur_tsf, data, sizeof(tsf_t)); - - if (cur_tsf.low == 0) { - DHD_INFO((" ---- 0 TSF, do not update, return\n")); - return; - } - - if (cur_tsf.low > prev_tsf.low) - tsf_delta = (cur_tsf.low - prev_tsf.low); - else { - DHD_INFO((" ---- tsf low is smaller cur_tsf= %08X, prev_tsf=%08X, \n", - cur_tsf.low, prev_tsf.low)); - if (cur_tsf.high > prev_tsf.high) { - tsf_delta = cur_tsf.low + (0xFFFFFFFF - prev_tsf.low); - DHD_INFO((" ---- Wrap around tsf coutner adjusted TSF=%08X\n", tsf_delta)); - } - else - return; /* do not update */ - } - - if (tsf_delta) { - hfactor = cyc_delta / tsf_delta; - tmp = (cyc_delta - (hfactor * tsf_delta))*10; - dec1 = tmp/tsf_delta; - dec2 = ((tmp - dec1*tsf_delta)*10) / tsf_delta; - tmp = (tmp - (dec1*tsf_delta))*10; - dec3 = ((tmp - dec2*tsf_delta)*10) / tsf_delta; - - if (dec3 > 4) { - if (dec2 == 9) { - dec2 = 0; - if (dec1 == 9) { - dec1 = 0; - hfactor++; - } - else { - dec1++; - } - } - else - dec2++; - } - } - - if (hfactor) { - htsf = ((cyc_delta * 10) / (hfactor*10+dec1)) + prev_tsf.low; - dhd->htsf.coef = hfactor; - dhd->htsf.last_cycle = cur_cycle; - dhd->htsf.last_tsf = cur_tsf.low; - dhd->htsf.coefdec1 = dec1; - dhd->htsf.coefdec2 = dec2; - } - else { - htsf = prev_tsf.low; - } -} - -#endif /* WLMEDIA_HTSF */ diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_linux_sched.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_linux_sched.c deleted file mode 100644 index 76336b3..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_linux_sched.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Expose some of the kernel scheduler routines - * - * Copyright (C) 1999-2011, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_linux_sched.c 291086 2011-10-21 01:17:24Z $ - */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <typedefs.h> -#include <linuxver.h> - -int setScheduler(struct task_struct *p, int policy, struct sched_param *param) -{ - int rc = 0; -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)) - rc = sched_setscheduler(p, policy, param); -#endif /* LinuxVer */ - return rc; -} diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_proto.h b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_proto.h deleted file mode 100644 index 8cc2542..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_proto.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Header file describing the internal (inter-module) DHD interfaces. - * - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2011, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_proto.h 303834 2011-12-20 06:17:39Z $ - */ - -#ifndef _dhd_proto_h_ -#define _dhd_proto_h_ - -#include <dhdioctl.h> -#include <wlioctl.h> - -#ifndef IOCTL_RESP_TIMEOUT -#define IOCTL_RESP_TIMEOUT 5000 /* In milli second */ -#endif /* IOCTL_RESP_TIMEOUT */ - -/* - * Exported from the dhd protocol module (dhd_cdc, dhd_rndis) - */ - -/* Linkage, sets prot link and updates hdrlen in pub */ -extern int dhd_prot_attach(dhd_pub_t *dhdp); - -/* Unlink, frees allocated protocol memory (including dhd_prot) */ -extern void dhd_prot_detach(dhd_pub_t *dhdp); - -/* Initialize protocol: sync w/dongle state. - * Sets dongle media info (iswl, drv_version, mac address). - */ -extern int dhd_prot_init(dhd_pub_t *dhdp); - -/* Stop protocol: sync w/dongle state. */ -extern void dhd_prot_stop(dhd_pub_t *dhdp); -#ifdef PROP_TXSTATUS -extern int dhd_wlfc_init(dhd_pub_t *dhd); -extern void dhd_wlfc_deinit(dhd_pub_t *dhd); -#endif - -/* Add any protocol-specific data header. - * Caller must reserve prot_hdrlen prepend space. - */ -extern void dhd_prot_hdrpush(dhd_pub_t *, int ifidx, void *txp); - -/* Remove any protocol-specific data header. */ -extern int dhd_prot_hdrpull(dhd_pub_t *, int *ifidx, void *rxp, uchar *buf, uint *len); - -/* Use protocol to issue ioctl to dongle */ -extern int dhd_prot_ioctl(dhd_pub_t *dhd, int ifidx, wl_ioctl_t * ioc, void * buf, int len); - -/* Handles a protocol control response asynchronously */ -extern int dhd_prot_ctl_complete(dhd_pub_t *dhd); - -/* Check for and handle local prot-specific iovar commands */ -extern int dhd_prot_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set); - -/* Add prot dump output to a buffer */ -extern void dhd_prot_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf); - -/* Update local copy of dongle statistics */ -extern void dhd_prot_dstats(dhd_pub_t *dhdp); - -extern int dhd_ioctl(dhd_pub_t * dhd_pub, dhd_ioctl_t *ioc, void * buf, uint buflen); - -extern int dhd_preinit_ioctls(dhd_pub_t *dhd); - -#ifdef PROP_TXSTATUS -extern int dhd_wlfc_enque_sendq(void* state, int prec, void* p); -extern int dhd_wlfc_commit_packets(void* state, f_commitpkt_t fcommit, void* commit_ctx); -extern void dhd_wlfc_cleanup(dhd_pub_t *dhd); -#endif /* PROP_TXSTATUS */ - -extern int dhd_process_pkt_reorder_info(dhd_pub_t *dhd, uchar *reorder_info_buf, - uint reorder_info_len, void **pkt, uint32 *free_buf_count); - - -/******************************** - * For version-string expansion * - */ -#if defined(BDC) -#define DHD_PROTOCOL "bdc" -#elif defined(CDC) -#define DHD_PROTOCOL "cdc" -#elif defined(RNDIS) -#define DHD_PROTOCOL "rndis" -#else -#define DHD_PROTOCOL "unknown" -#endif /* proto */ - -#endif /* _dhd_proto_h_ */ diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sdio.c b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sdio.c deleted file mode 100644 index 211c865..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sdio.c +++ /dev/null @@ -1,7153 +0,0 @@ -/* - * DHD Bus Module for SDIO - * - * Copyright (C) 1999-2012, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_sdio.c 309548 2012-01-20 01:13:08Z $ - */ - -#include <typedefs.h> -#include <osl.h> -#include <bcmsdh.h> - -#ifdef BCMEMBEDIMAGE -#include BCMEMBEDIMAGE -#endif /* BCMEMBEDIMAGE */ - -#include <bcmdefs.h> -#include <bcmutils.h> -#include <bcmendian.h> -#include <bcmdevs.h> - -#include <siutils.h> -#include <hndpmu.h> -#include <hndsoc.h> -#include <bcmsdpcm.h> -#if defined(DHD_DEBUG) -#include <hndrte_armtrap.h> -#include <hndrte_cons.h> -#endif /* defined(DHD_DEBUG) */ -#include <sbchipc.h> -#include <sbhnddma.h> - -#include <sdio.h> -#include <sbsdio.h> -#include <sbsdpcmdev.h> -#include <bcmsdpcm.h> -#include <bcmsdbus.h> - -#include <proto/ethernet.h> -#include <proto/802.1d.h> -#include <proto/802.11.h> - -#include <dngl_stats.h> -#include <dhd.h> -#include <dhd_bus.h> -#include <dhd_proto.h> -#include <dhd_dbg.h> -#include <dhdioctl.h> -#include <sdiovar.h> - -#ifndef DHDSDIO_MEM_DUMP_FNAME -#define DHDSDIO_MEM_DUMP_FNAME "mem_dump" -#endif - -#define QLEN 256 /* bulk rx and tx queue lengths */ -#define FCHI (QLEN - 10) -#define FCLOW (FCHI / 2) -#define PRIOMASK 7 - -#define TXRETRIES 2 /* # of retries for tx frames */ - -#define DHD_RXBOUND 50 /* Default for max rx frames in one scheduling */ - -#define DHD_TXBOUND 20 /* Default for max tx frames in one scheduling */ - -#define DHD_TXMINMAX 1 /* Max tx frames if rx still pending */ - -#define MEMBLOCK 2048 /* Block size used for downloading of dongle image */ -#define MAX_NVRAMBUF_SIZE 4096 /* max nvram buf size */ -#define MAX_DATA_BUF (32 * 1024) /* Must be large enough to hold biggest possible glom */ - -#ifndef DHD_FIRSTREAD -#define DHD_FIRSTREAD 32 -#endif -#if !ISPOWEROF2(DHD_FIRSTREAD) -#error DHD_FIRSTREAD is not a power of 2! -#endif - -/* Total length of frame header for dongle protocol */ -#define SDPCM_HDRLEN (SDPCM_FRAMETAG_LEN + SDPCM_SWHEADER_LEN) -#ifdef SDTEST -#define SDPCM_RESERVE (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN) -#else -#define SDPCM_RESERVE (SDPCM_HDRLEN + DHD_SDALIGN) -#endif - -/* Space for header read, limit for data packets */ -#ifndef MAX_HDR_READ -#define MAX_HDR_READ 32 -#endif -#if !ISPOWEROF2(MAX_HDR_READ) -#error MAX_HDR_READ is not a power of 2! -#endif - -#define MAX_RX_DATASZ 2048 - -/* Maximum milliseconds to wait for F2 to come up */ -#define DHD_WAIT_F2RDY 3000 - -/* Bump up limit on waiting for HT to account for first startup; - * if the image is doing a CRC calculation before programming the PMU - * for HT availability, it could take a couple hundred ms more, so - * max out at a 1 second (1000000us). - */ -#if (PMU_MAX_TRANSITION_DLY <= 1000000) -#undef PMU_MAX_TRANSITION_DLY -#define PMU_MAX_TRANSITION_DLY 1000000 -#endif - -/* Value for ChipClockCSR during initial setup */ -#define DHD_INIT_CLKCTL1 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ) -#define DHD_INIT_CLKCTL2 (SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP) - -/* Flags for SDH calls */ -#define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED) - -/* Packet free applicable unconditionally for sdio and sdspi. Conditional if - * bufpool was present for gspi bus. - */ -#define PKTFREE2() if ((bus->bus != SPI_BUS) || bus->usebufpool) \ - PKTFREE(bus->dhd->osh, pkt, FALSE); -DHD_SPINWAIT_SLEEP_INIT(sdioh_spinwait_sleep); -#if defined(OOB_INTR_ONLY) -extern void bcmsdh_set_irq(int flag); -#endif /* defined(OOB_INTR_ONLY) */ -#ifdef PROP_TXSTATUS -extern void dhd_wlfc_txcomplete(dhd_pub_t *dhd, void *txp, bool success); -#endif - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) -DEFINE_MUTEX(_dhd_sdio_mutex_lock_); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ - -#ifdef DHD_DEBUG -/* Device console log buffer state */ -#define CONSOLE_LINE_MAX 192 -#define CONSOLE_BUFFER_MAX 2024 -typedef struct dhd_console { - uint count; /* Poll interval msec counter */ - uint log_addr; /* Log struct address (fixed) */ - hndrte_log_t log; /* Log struct (host copy) */ - uint bufsize; /* Size of log buffer */ - uint8 *buf; /* Log buffer (host copy) */ - uint last; /* Last buffer read index */ -} dhd_console_t; -#endif /* DHD_DEBUG */ - -#ifdef BCM4334_CHECK_CHIP_REV -#define REV_ID_ADDR 0x1E008F90 -uint g_chipver; -char chipver_tag[4]; -char fw_down_path[MOD_PARAM_PATHLEN]; -#endif - -#define REMAP_ENAB(bus) ((bus)->remap) -#define REMAP_ISADDR(bus, a) (((a) >= ((bus)->orig_ramsize)) && ((a) < ((bus)->ramsize))) -#define KSO_ENAB(bus) ((bus)->kso) -#define SR_ENAB(bus) ((bus)->_srenab) -#define SLPAUTO_ENAB(bus) ((SR_ENAB(bus)) && ((bus)->_slpauto)) -#define MIN_RSRC_ADDR (SI_ENUM_BASE + 0x618) -#define MIN_RSRC_SR 0x3 -#define CORE_CAPEXT_ADDR (SI_ENUM_BASE + 0x64c) -#define CORE_CAPEXT_SR_SUPPORTED_MASK (1 << 1) -#define RCTL_MACPHY_DISABLE_MASK (1 << 26) -#define RCTL_LOGIC_DISABLE_MASK (1 << 27) - -#define OOB_WAKEUP_ENAB(bus) ((bus)->_oobwakeup) -#define GPIO_DEV_SRSTATE 16 /* Host gpio17 mapped to device gpio0 SR state */ -#define GPIO_DEV_SRSTATE_TIMEOUT 320000 /* 320ms */ -#define GPIO_DEV_WAKEUP 17 /* Host gpio17 mapped to device gpio1 wakeup */ -#define CC_CHIPCTRL2_GPIO1_WAKEUP (1 << 0) - - -/* Private data for SDIO bus interaction */ -typedef struct dhd_bus { - dhd_pub_t *dhd; - - bcmsdh_info_t *sdh; /* Handle for BCMSDH calls */ - si_t *sih; /* Handle for SI calls */ - char *vars; /* Variables (from CIS and/or other) */ - uint varsz; /* Size of variables buffer */ - uint32 sbaddr; /* Current SB window pointer (-1, invalid) */ - - sdpcmd_regs_t *regs; /* Registers for SDIO core */ - uint sdpcmrev; /* SDIO core revision */ - uint armrev; /* CPU core revision */ - uint ramrev; /* SOCRAM core revision */ - uint32 ramsize; /* Size of RAM in SOCRAM (bytes) */ - uint32 orig_ramsize; /* Size of RAM in SOCRAM (bytes) */ - uint32 srmemsize; /* Size of SRMEM */ - - uint32 bus; /* gSPI or SDIO bus */ - uint32 hostintmask; /* Copy of Host Interrupt Mask */ - uint32 intstatus; /* Intstatus bits (events) pending */ - bool dpc_sched; /* Indicates DPC schedule (intrpt rcvd) */ - bool fcstate; /* State of dongle flow-control */ - - uint16 cl_devid; /* cached devid for dhdsdio_probe_attach() */ - char *fw_path; /* module_param: path to firmware image */ - char *nv_path; /* module_param: path to nvram vars file */ - const char *nvram_params; /* user specified nvram params. */ - - uint blocksize; /* Block size of SDIO transfers */ - uint roundup; /* Max roundup limit */ - - struct pktq txq; /* Queue length used for flow-control */ - uint8 flowcontrol; /* per prio flow control bitmask */ - uint8 tx_seq; /* Transmit sequence number (next) */ - uint8 tx_max; /* Maximum transmit sequence allowed */ - - uint8 hdrbuf[MAX_HDR_READ + DHD_SDALIGN]; - uint8 *rxhdr; /* Header of current rx frame (in hdrbuf) */ - uint16 nextlen; /* Next Read Len from last header */ - uint8 rx_seq; /* Receive sequence number (expected) */ - bool rxskip; /* Skip receive (awaiting NAK ACK) */ - - void *glomd; /* Packet containing glomming descriptor */ - void *glom; /* Packet chain for glommed superframe */ - uint glomerr; /* Glom packet read errors */ - - uint8 *rxbuf; /* Buffer for receiving control packets */ - uint rxblen; /* Allocated length of rxbuf */ - uint8 *rxctl; /* Aligned pointer into rxbuf */ - uint8 *databuf; /* Buffer for receiving big glom packet */ - uint8 *dataptr; /* Aligned pointer into databuf */ - uint rxlen; /* Length of valid data in buffer */ - - uint8 sdpcm_ver; /* Bus protocol reported by dongle */ - - bool intr; /* Use interrupts */ - bool poll; /* Use polling */ - bool ipend; /* Device interrupt is pending */ - bool intdis; /* Interrupts disabled by isr */ - uint intrcount; /* Count of device interrupt callbacks */ - uint lastintrs; /* Count as of last watchdog timer */ - uint spurious; /* Count of spurious interrupts */ - uint pollrate; /* Ticks between device polls */ - uint polltick; /* Tick counter */ - uint pollcnt; /* Count of active polls */ - -#ifdef DHD_DEBUG - dhd_console_t console; /* Console output polling support */ - uint console_addr; /* Console address from shared struct */ -#endif /* DHD_DEBUG */ - - uint regfails; /* Count of R_REG/W_REG failures */ - - uint clkstate; /* State of sd and backplane clock(s) */ - bool activity; /* Activity flag for clock down */ - int32 idletime; /* Control for activity timeout */ - int32 idlecount; /* Activity timeout counter */ - int32 idleclock; /* How to set bus driver when idle */ - int32 sd_divisor; /* Speed control to bus driver */ - int32 sd_mode; /* Mode control to bus driver */ - int32 sd_rxchain; /* If bcmsdh api accepts PKT chains */ - bool use_rxchain; /* If dhd should use PKT chains */ - bool sleeping; /* Is SDIO bus sleeping? */ - uint rxflow_mode; /* Rx flow control mode */ - bool rxflow; /* Is rx flow control on */ - uint prev_rxlim_hit; /* Is prev rx limit exceeded (per dpc schedule) */ - bool alp_only; /* Don't use HT clock (ALP only) */ - /* Field to decide if rx of control frames happen in rxbuf or lb-pool */ - bool usebufpool; - -#ifdef SDTEST - /* external loopback */ - bool ext_loop; - uint8 loopid; - - /* pktgen configuration */ - uint pktgen_freq; /* Ticks between bursts */ - uint pktgen_count; /* Packets to send each burst */ - uint pktgen_print; /* Bursts between count displays */ - uint pktgen_total; /* Stop after this many */ - uint pktgen_minlen; /* Minimum packet data len */ - uint pktgen_maxlen; /* Maximum packet data len */ - uint pktgen_mode; /* Configured mode: tx, rx, or echo */ - uint pktgen_stop; /* Number of tx failures causing stop */ - - /* active pktgen fields */ - uint pktgen_tick; /* Tick counter for bursts */ - uint pktgen_ptick; /* Burst counter for printing */ - uint pktgen_sent; /* Number of test packets generated */ - uint pktgen_rcvd; /* Number of test packets received */ - uint pktgen_fail; /* Number of failed send attempts */ - uint16 pktgen_len; /* Length of next packet to send */ -#define PKTGEN_RCV_IDLE (0) -#define PKTGEN_RCV_ONGOING (1) - uint16 pktgen_rcv_state; /* receive state */ - uint pktgen_rcvd_rcvsession; /* test pkts rcvd per rcv session. */ -#endif /* SDTEST */ - - /* Some additional counters */ - uint tx_sderrs; /* Count of tx attempts with sd errors */ - uint fcqueued; /* Tx packets that got queued */ - uint rxrtx; /* Count of rtx requests (NAK to dongle) */ - uint rx_toolong; /* Receive frames too long to receive */ - uint rxc_errors; /* SDIO errors when reading control frames */ - uint rx_hdrfail; /* SDIO errors on header reads */ - uint rx_badhdr; /* Bad received headers (roosync?) */ - uint rx_badseq; /* Mismatched rx sequence number */ - uint fc_rcvd; /* Number of flow-control events received */ - uint fc_xoff; /* Number which turned on flow-control */ - uint fc_xon; /* Number which turned off flow-control */ - uint rxglomfail; /* Failed deglom attempts */ - uint rxglomframes; /* Number of glom frames (superframes) */ - uint rxglompkts; /* Number of packets from glom frames */ - uint f2rxhdrs; /* Number of header reads */ - uint f2rxdata; /* Number of frame data reads */ - uint f2txdata; /* Number of f2 frame writes */ - uint f1regdata; /* Number of f1 register accesses */ - - uint8 *ctrl_frame_buf; - uint32 ctrl_frame_len; - bool ctrl_frame_stat; - uint32 rxint_mode; /* rx interrupt mode */ - bool remap; /* Contiguous 1MB RAM: 512K socram + 512K devram - * Available with socram rev 16 - * Remap region not DMA-able - */ - bool kso; - bool _slpauto; - bool _oobwakeup; - bool _srenab; - bool readframes; -} dhd_bus_t; - -/* clkstate */ -#define CLK_NONE 0 -#define CLK_SDONLY 1 -#define CLK_PENDING 2 /* Not used yet */ -#define CLK_AVAIL 3 - -#define DHD_NOPMU(dhd) (FALSE) - -#ifdef DHD_DEBUG -static int qcount[NUMPRIO]; -static int tx_packets[NUMPRIO]; -#endif /* DHD_DEBUG */ - -/* Deferred transmit */ -const uint dhd_deferred_tx = 1; - -extern uint dhd_watchdog_ms; -extern void dhd_os_wd_timer(void *bus, uint wdtick); - -/* Tx/Rx bounds */ -uint dhd_txbound; -uint dhd_rxbound; -uint dhd_txminmax = DHD_TXMINMAX; - -/* override the RAM size if possible */ -#define DONGLE_MIN_MEMSIZE (128 *1024) -int dhd_dongle_memsize; - -static bool dhd_doflow; -static bool dhd_alignctl; - -static bool sd1idle; - -static bool retrydata; -#define RETRYCHAN(chan) (((chan) == SDPCM_EVENT_CHANNEL) || retrydata) - -static const uint watermark = 8; -static const uint mesbusyctrl = 0; -static const uint firstread = DHD_FIRSTREAD; - -#define HDATLEN (firstread - (SDPCM_HDRLEN)) - -/* Retry count for register access failures */ -static const uint retry_limit = 2; - -/* Force even SD lengths (some host controllers mess up on odd bytes) */ -static bool forcealign; - -/* Flag to indicate if we should download firmware on driver load */ -uint dhd_download_fw_on_driverload = TRUE; - -#define ALIGNMENT 4 - -#if defined(OOB_INTR_ONLY) && defined(HW_OOB) -extern void bcmsdh_enable_hw_oob_intr(void *sdh, bool enable); -#endif - -#if defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) -#error OOB_INTR_ONLY is NOT working with SDIO_ISR_THREAD -#endif /* defined(OOB_INTR_ONLY) && defined(SDIO_ISR_THREAD) */ -#define PKTALIGN(osh, p, len, align) \ - do { \ - uint datalign; \ - datalign = (uintptr)PKTDATA((osh), (p)); \ - datalign = ROUNDUP(datalign, (align)) - datalign; \ - ASSERT(datalign < (align)); \ - ASSERT(PKTLEN((osh), (p)) >= ((len) + datalign)); \ - if (datalign) \ - PKTPULL((osh), (p), datalign); \ - PKTSETLEN((osh), (p), (len)); \ - } while (0) - -/* Limit on rounding up frames */ -static const uint max_roundup = 512; - -/* Try doing readahead */ -static bool dhd_readahead; - - -/* To check if there's window offered */ -#define DATAOK(bus) \ - (((uint8)(bus->tx_max - bus->tx_seq) > 1) && \ - (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) - -/* To check if there's window offered for ctrl frame */ -#define TXCTLOK(bus) \ - (((uint8)(bus->tx_max - bus->tx_seq) != 0) && \ - (((uint8)(bus->tx_max - bus->tx_seq) & 0x80) == 0)) - -/* Macros to get register read/write status */ -/* NOTE: these assume a local dhdsdio_bus_t *bus! */ -#define R_SDREG(regvar, regaddr, retryvar) \ -do { \ - retryvar = 0; \ - do { \ - regvar = R_REG(bus->dhd->osh, regaddr); \ - } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ - if (retryvar) { \ - bus->regfails += (retryvar-1); \ - if (retryvar > retry_limit) { \ - DHD_ERROR(("%s: FAILED" #regvar "READ, LINE %d\n", \ - __FUNCTION__, __LINE__)); \ - regvar = 0; \ - } \ - } \ -} while (0) - -#define W_SDREG(regval, regaddr, retryvar) \ -do { \ - retryvar = 0; \ - do { \ - W_REG(bus->dhd->osh, regaddr, regval); \ - } while (bcmsdh_regfail(bus->sdh) && (++retryvar <= retry_limit)); \ - if (retryvar) { \ - bus->regfails += (retryvar-1); \ - if (retryvar > retry_limit) \ - DHD_ERROR(("%s: FAILED REGISTER WRITE, LINE %d\n", \ - __FUNCTION__, __LINE__)); \ - } \ -} while (0) - -#define BUS_WAKE(bus) \ - do { \ - if ((bus)->sleeping) \ - dhdsdio_bussleep((bus), FALSE); \ - } while (0); - -/* - * pktavail interrupts from dongle to host can be managed in 3 different ways - * whenever there is a packet available in dongle to transmit to host. - * - * Mode 0: Dongle writes the software host mailbox and host is interrupted. - * Mode 1: (sdiod core rev >= 4) - * Device sets a new bit in the intstatus whenever there is a packet - * available in fifo. Host can't clear this specific status bit until all the - * packets are read from the FIFO. No need to ack dongle intstatus. - * Mode 2: (sdiod core rev >= 4) - * Device sets a bit in the intstatus, and host acks this by writing - * one to this bit. Dongle won't generate anymore packet interrupts - * until host reads all the packets from the dongle and reads a zero to - * figure that there are no more packets. No need to disable host ints. - * Need to ack the intstatus. - */ - -#define SDIO_DEVICE_HMB_RXINT 0 /* default old way */ -#define SDIO_DEVICE_RXDATAINT_MODE_0 1 /* from sdiod rev 4 */ -#define SDIO_DEVICE_RXDATAINT_MODE_1 2 /* from sdiod rev 4 */ - - -#define FRAME_AVAIL_MASK(bus) \ - ((bus->rxint_mode == SDIO_DEVICE_HMB_RXINT) ? I_HMB_FRAME_IND : I_XMTDATA_AVAIL) - -#define DHD_BUS SDIO_BUS - -#define PKT_AVAILABLE(bus, intstatus) ((intstatus) & (FRAME_AVAIL_MASK(bus))) - -#define HOSTINTMASK (I_HMB_SW_MASK | I_CHIPACTIVE) - -#define GSPI_PR55150_BAILOUT - -#ifdef SDTEST -static void dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq); -static void dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count); -#endif - -#ifdef DHD_DEBUG -static int dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size); -static int dhd_serialconsole(dhd_bus_t *bus, bool get, bool enable, int *bcmerror); -#endif /* DHD_DEBUG */ - -static int dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap); -static int dhdsdio_download_state(dhd_bus_t *bus, bool enter); - -static void dhdsdio_release(dhd_bus_t *bus, osl_t *osh); -static void dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh); -static void dhdsdio_disconnect(void *ptr); -static bool dhdsdio_chipmatch(uint16 chipid); -static bool dhdsdio_probe_attach(dhd_bus_t *bus, osl_t *osh, void *sdh, - void * regsva, uint16 devid); -static bool dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh); -static bool dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh); -static void dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, - bool reset_flag); - -static void dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size); -static int dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, - void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); -static int dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, - uint8 *buf, uint nbytes, - void *pkt, bcmsdh_cmplt_fn_t complete, void *handle); - -static bool dhdsdio_download_firmware(dhd_bus_t *bus, osl_t *osh, void *sdh); -static int _dhdsdio_download_firmware(dhd_bus_t *bus); - -static int dhdsdio_download_code_file(dhd_bus_t *bus, char *image_path); -static int dhdsdio_download_nvram(dhd_bus_t *bus); -#ifdef BCMEMBEDIMAGE -static int dhdsdio_download_code_array(dhd_bus_t *bus); -#endif -static int dhdsdio_bussleep(dhd_bus_t *bus, bool sleep); -static int dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok); -static uint8 dhdsdio_sleepcsr_get(dhd_bus_t *bus); - -#ifdef WLMEDIA_HTSF -#include <htsf.h> -extern uint32 dhd_get_htsf(void *dhd, int ifidx); -#endif /* WLMEDIA_HTSF */ - -static void -dhd_dongle_setmemsize(struct dhd_bus *bus, int mem_size) -{ - int32 min_size = DONGLE_MIN_MEMSIZE; - /* Restrict the memsize to user specified limit */ - DHD_ERROR(("user: Restrict the dongle ram size to %d, min accepted %d\n", - dhd_dongle_memsize, min_size)); - if ((dhd_dongle_memsize > min_size) && - (dhd_dongle_memsize < (int32)bus->orig_ramsize)) - bus->ramsize = dhd_dongle_memsize; -} - -static int -dhdsdio_set_siaddr_window(dhd_bus_t *bus, uint32 address) -{ - int err = 0; - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, - (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); - if (!err) - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRMID, - (address >> 16) & SBSDIO_SBADDRMID_MASK, &err); - if (!err) - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRHIGH, - (address >> 24) & SBSDIO_SBADDRHIGH_MASK, &err); - return err; -} - - -#ifdef USE_OOB_GPIO1 -static int -dhdsdio_oobwakeup_init(dhd_bus_t *bus) -{ - uint32 val, addr, data; - - bcmsdh_gpioouten(bus->sdh, GPIO_DEV_WAKEUP); - - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); - data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); - - /* Set device for gpio1 wakeup */ - bcmsdh_reg_write(bus->sdh, addr, 4, 2); - val = bcmsdh_reg_read(bus->sdh, data, 4); - val |= CC_CHIPCTRL2_GPIO1_WAKEUP; - bcmsdh_reg_write(bus->sdh, data, 4, val); - - bus->_oobwakeup = TRUE; - - return 0; -} -#endif /* USE_OOB_GPIO1 */ - -#ifdef BCM4334_CHIP -/* - * Query if FW is in SR mode - */ -static bool -dhdsdio_sr_cap(dhd_bus_t *bus) -{ - bool cap = FALSE; - uint32 min = 0, core_capext, data; - - core_capext = bcmsdh_reg_read(bus->sdh, CORE_CAPEXT_ADDR, 4); - if (!(core_capext & CORE_CAPEXT_SR_SUPPORTED_MASK)) - return FALSE; - - if (bus->sih->chip == BCM4324_CHIP_ID) { - min = bcmsdh_reg_read(bus->sdh, MIN_RSRC_ADDR, 4); - if (min == MIN_RSRC_SR) - cap = TRUE; - } else { - data = bcmsdh_reg_read(bus->sdh, - SI_ENUM_BASE + OFFSETOF(chipcregs_t, retention_ctl), 4); - if ((data & (RCTL_MACPHY_DISABLE_MASK | RCTL_LOGIC_DISABLE_MASK)) == 0) - cap = TRUE; - } - - return cap; -} - -static int -dhdsdio_srwar_init(dhd_bus_t *bus) -{ - - bcmsdh_gpio_init(bus->sdh); - -#ifdef USE_OOB_GPIO1 - dhdsdio_oobwakeup_init(bus); -#endif - - - return 0; -} - -static int -dhdsdio_sr_init(dhd_bus_t *bus) -{ - uint8 val; - int err = 0; - - if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) - dhdsdio_srwar_init(bus); - - - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); - val |= 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT; - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, - 1 << SBSDIO_FUNC1_WCTRL_HTWAIT_SHIFT, &err); - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_WAKEUPCTRL, NULL); - - /* Add CMD14 Support */ - dhdsdio_devcap_set(bus, - (SDIOD_CCCR_BRCM_CARDCAP_CMD14_SUPPORT | SDIOD_CCCR_BRCM_CARDCAP_CMD14_EXT)); - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, SBSDIO_FORCE_HT, &err); - - bus->_slpauto = dhd_slpauto ? TRUE : FALSE; - - bus->_srenab = TRUE; - - return 0; -} -#endif /* BCM4334_CHIP */ - -/* - * FIX: Be sure KSO bit is enabled - * Currently, it's defaulting to 0 which should be 1. - */ -static int -dhdsdio_clk_kso_init(dhd_bus_t *bus) -{ - uint8 val; - int err = 0; - - /* set flag */ - bus->kso = TRUE; - - /* - * Enable KeepSdioOn (KSO) bit for normal operation - * Default is 0 (4334A0) so set it. Fixed in B0. - */ - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, NULL); - if (!(val & SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { - val |= (SBSDIO_FUNC1_SLEEPCSR_KSO_EN << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err); - if (err) - DHD_ERROR(("%s: SBSDIO_FUNC1_SLEEPCSR err: 0x%x\n", __FUNCTION__, err)); - } - - return 0; -} - -static int -dhdsdio_clk_kso_enab(dhd_bus_t *bus, bool on) -{ - uint8 val = 0; - int err = 0; - - /* Don't read here since sdio could be off so just write only */ - val |= (on << SBSDIO_FUNC1_SLEEPCSR_KSO_SHIFT); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, val, &err); - - if (err) - DHD_TRACE(("%s: KSO toggle %d failed: %d\n", __FUNCTION__, on, err)); - return 0; -} - -static int -dhdsdio_clk_kso_iovar(dhd_bus_t *bus, bool on) -{ - int err = 0; - - if (on == FALSE) { - - BUS_WAKE(bus); - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - DHD_ERROR(("%s: KSO disable clk: 0x%x\n", __FUNCTION__, - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err))); - dhdsdio_clk_kso_enab(bus, FALSE); - } else { - DHD_ERROR(("%s: KSO enable\n", __FUNCTION__)); - - /* Make sure we have SD bus access */ - if (bus->clkstate == CLK_NONE) { - DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__)); - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - } - - /* Double-write to be safe in case transition of AOS */ - dhdsdio_clk_kso_enab(bus, TRUE); - dhdsdio_clk_kso_enab(bus, TRUE); - OSL_DELAY(4000); - - /* Wait for device ready during transition to wake-up */ - SPINWAIT(((dhdsdio_sleepcsr_get(bus)) != - (SBSDIO_FUNC1_SLEEPCSR_KSO_MASK | - SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), - (10000)); - - DHD_ERROR(("%s: sleepcsr: 0x%x\n", __FUNCTION__, - dhdsdio_sleepcsr_get(bus))); - } - - bus->kso = on; - - return 0; -} - -static uint8 -dhdsdio_sleepcsr_get(dhd_bus_t *bus) -{ - int err = 0; - uint8 val = 0; - - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_SLEEPCSR, &err); - if (err) - DHD_TRACE(("Failed to read SLEEPCSR: %d\n", err)); - - return val; -} - -uint8 -dhdsdio_devcap_get(dhd_bus_t *bus) -{ - return bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, NULL); -} - -static int -dhdsdio_devcap_set(dhd_bus_t *bus, uint8 cap) -{ - int err = 0; - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_BRCM_CARDCAP, cap, &err); - if (err) - DHD_ERROR(("%s: devcap set err: 0x%x\n", __FUNCTION__, err)); - - return 0; -} - -static int -dhdsdio_clk_devsleep_iovar(dhd_bus_t *bus, bool on) -{ - int err = 0, retry; - uint8 val; - - retry = 0; - if (on == TRUE) { - /* Enter Sleep */ - - /* Be sure we request clk before going to sleep - * so we can wake-up with clk request already set - * else device can go back to sleep immediately - */ - if (!SLPAUTO_ENAB(bus)) - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - else { - val = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if ((val & SBSDIO_CSR_MASK) == 0) { - DHD_ERROR(("%s: No clock before enter sleep:0x%x\n", - __FUNCTION__, val)); - - /* Reset clock request */ - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - SBSDIO_ALP_AVAIL_REQ, &err); - DHD_ERROR(("%s: clock before sleep:0x%x\n", __FUNCTION__, - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err))); - } - } - - DHD_TRACE(("%s: clk before sleep: 0x%x\n", __FUNCTION__, - bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err))); -#ifdef USE_CMD14 - err = bcmsdh_sleep(bus->sdh, TRUE); -#else - err = dhdsdio_clk_kso_enab(bus, FALSE); - if (OOB_WAKEUP_ENAB(bus)) - err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, FALSE); /* GPIO_1 is off */ -#endif - } else { - /* Exit Sleep */ - /* Make sure we have SD bus access */ - if (bus->clkstate == CLK_NONE) { - DHD_ERROR(("%s: Request SD clk\n", __FUNCTION__)); - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - } - - if ((bus->sih->chip == BCM4334_CHIP_ID) && (bus->sih->chiprev == 2)) { - SPINWAIT((bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) != TRUE), - GPIO_DEV_SRSTATE_TIMEOUT); - - if (bcmsdh_gpioin(bus->sdh, GPIO_DEV_SRSTATE) == FALSE) { - DHD_ERROR(("ERROR: GPIO_DEV_SRSTATE still low!\n")); - } - } -#ifdef USE_CMD14 - err = bcmsdh_sleep(bus->sdh, FALSE); - if (SLPAUTO_ENAB(bus) && (err != 0)) { - OSL_DELAY(10000); - DHD_TRACE(("%s: Resync device sleep\n", __FUNCTION__)); - - /* Toggle sleep to resync with host and device */ - err = bcmsdh_sleep(bus->sdh, TRUE); - OSL_DELAY(10000); - err = bcmsdh_sleep(bus->sdh, FALSE); - - if (err) { - OSL_DELAY(10000); - DHD_ERROR(("%s: CMD14 exit failed again!\n", __FUNCTION__)); - - /* Toggle sleep to resync with host and device */ - err = bcmsdh_sleep(bus->sdh, TRUE); - OSL_DELAY(10000); - err = bcmsdh_sleep(bus->sdh, FALSE); - if (err) { - DHD_ERROR(("%s: CMD14 exit failed twice!\n", __FUNCTION__)); - DHD_ERROR(("%s: FATAL: Device non-response!\n", - __FUNCTION__)); - err = 0; - } - } - } -#else - if (OOB_WAKEUP_ENAB(bus)) - err = bcmsdh_gpioout(bus->sdh, GPIO_DEV_WAKEUP, TRUE); /* GPIO_1 is on */ - - do { - err = dhdsdio_clk_kso_enab(bus, TRUE); - OSL_DELAY(10000); - } while ((err != 0) && (++retry < 3)); - - if (err != 0) { - DHD_ERROR(("ERROR: kso set failed retry: %d\n", retry)); - err = 0; /* continue anyway */ - } -#endif /* !USE_CMD14 */ - - if (err == 0) { - uint8 csr; - - /* Wait for device ready during transition to wake-up */ - SPINWAIT((((csr = dhdsdio_sleepcsr_get(bus)) & - SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK) != - (SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)), (10000)); - - DHD_TRACE(("%s: ExitSleep sleepcsr: 0x%x\n", __FUNCTION__, csr)); - - if (!(csr & SBSDIO_FUNC1_SLEEPCSR_DEVON_MASK)) { - DHD_ERROR(("%s:ERROR: ExitSleep device NOT Ready! 0x%x\n", - __FUNCTION__, csr)); - err = BCME_NODEVICE; - } - - SPINWAIT((((csr = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err)) & SBSDIO_HT_AVAIL) != - (SBSDIO_HT_AVAIL)), (10000)); - - } - } - - /* Update if successful */ - if (err == 0) - bus->kso = on ? FALSE : TRUE; - else { - DHD_ERROR(("%s: Sleep request failed: on:%d err:%d\n", __FUNCTION__, on, err)); - } - - return err; -} - -/* Turn backplane clock on or off */ -static int -dhdsdio_htclk(dhd_bus_t *bus, bool on, bool pendok) -{ - int err; - uint8 clkctl, clkreq, devctl; - bcmsdh_info_t *sdh; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#if defined(OOB_INTR_ONLY) - pendok = FALSE; -#endif - clkctl = 0; - sdh = bus->sdh; - - - if (!KSO_ENAB(bus)) - return BCME_OK; - - if (SLPAUTO_ENAB(bus)) { - bus->clkstate = (on ? CLK_AVAIL : CLK_SDONLY); - return BCME_OK; - } - - if (on) { - /* Request HT Avail */ - clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); - if (err) { - DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); - return BCME_ERROR; - } - - if (pendok && - ((bus->sih->buscoretype == PCMCIA_CORE_ID) && (bus->sih->buscorerev == 9))) { - uint32 dummy, retries; - R_SDREG(dummy, &bus->regs->clockctlstatus, retries); - BCM_REFERENCE(dummy); - } - - /* Check current status */ - clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (err) { - DHD_ERROR(("%s: HT Avail read error: %d\n", __FUNCTION__, err)); - return BCME_ERROR; - } - - /* Go to pending and await interrupt if appropriate */ - if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { - /* Allow only clock-available interrupt */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - if (err) { - DHD_ERROR(("%s: Devctl access error setting CA: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - - devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - DHD_INFO(("CLKCTL: set PENDING\n")); - bus->clkstate = CLK_PENDING; - return BCME_OK; - } else if (bus->clkstate == CLK_PENDING) { - /* Cancel CA-only interrupt filter */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - } - - /* Otherwise, wait here (polling) for HT Avail */ - if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { - SPINWAIT_SLEEP(sdioh_spinwait_sleep, - ((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err)), - !SBSDIO_CLKAV(clkctl, bus->alp_only)), PMU_MAX_TRANSITION_DLY); - } - if (err) { - DHD_ERROR(("%s: HT Avail request error: %d\n", __FUNCTION__, err)); - return BCME_ERROR; - } - if (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { - DHD_ERROR(("%s: HT Avail timeout (%d): clkctl 0x%02x\n", - __FUNCTION__, PMU_MAX_TRANSITION_DLY, clkctl)); - return BCME_ERROR; - } - - /* Mark clock available */ - bus->clkstate = CLK_AVAIL; - DHD_INFO(("CLKCTL: turned ON\n")); - -#if defined(DHD_DEBUG) - if (bus->alp_only == TRUE) { -#if !defined(BCMLXSDMMC) - if (!SBSDIO_ALPONLY(clkctl)) { - DHD_ERROR(("%s: HT Clock, when ALP Only\n", __FUNCTION__)); - } -#endif /* !defined(BCMLXSDMMC) */ - } else { - if (SBSDIO_ALPONLY(clkctl)) { - DHD_ERROR(("%s: HT Clock should be on.\n", __FUNCTION__)); - } - } -#endif /* defined (DHD_DEBUG) */ - - bus->activity = TRUE; -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; -#endif /* DHD_USE_IDLECOUNT */ - } else { - clkreq = 0; - if (bus->clkstate == CLK_PENDING) { - /* Cancel CA-only interrupt filter */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - } - - bus->clkstate = CLK_SDONLY; - if (!SR_ENAB(bus)) { - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); - DHD_INFO(("CLKCTL: turned OFF\n")); - if (err) { - DHD_ERROR(("%s: Failed access turning clock off: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } - } - return BCME_OK; -} - -/* Change idle/active SD state */ -static int -dhdsdio_sdclk(dhd_bus_t *bus, bool on) -{ - int err; - int32 iovalue; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (on) { - if (bus->idleclock == DHD_IDLE_STOP) { - /* Turn on clock and restore mode */ - iovalue = 1; - err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error enabling sd_clock: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - - iovalue = bus->sd_mode; - err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error changing sd_mode: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } else if (bus->idleclock != DHD_IDLE_ACTIVE) { - /* Restore clock speed */ - iovalue = bus->sd_divisor; - err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error restoring sd_divisor: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } - bus->clkstate = CLK_SDONLY; - } else { - /* Stop or slow the SD clock itself */ - if ((bus->sd_divisor == -1) || (bus->sd_mode == -1)) { - DHD_TRACE(("%s: can't idle clock, divisor %d mode %d\n", - __FUNCTION__, bus->sd_divisor, bus->sd_mode)); - return BCME_ERROR; - } - if (bus->idleclock == DHD_IDLE_STOP) { - if (sd1idle) { - /* Change to SD1 mode and turn off clock */ - iovalue = 1; - err = bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error changing sd_clock: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } - - iovalue = 0; - err = bcmsdh_iovar_op(bus->sdh, "sd_clock", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error disabling sd_clock: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } else if (bus->idleclock != DHD_IDLE_ACTIVE) { - /* Set divisor to idle value */ - iovalue = bus->idleclock; - err = bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, - &iovalue, sizeof(iovalue), TRUE); - if (err) { - DHD_ERROR(("%s: error changing sd_divisor: %d\n", - __FUNCTION__, err)); - return BCME_ERROR; - } - } - bus->clkstate = CLK_NONE; - } - - return BCME_OK; -} - -/* Transition SD and backplane clock readiness */ -static int -dhdsdio_clkctl(dhd_bus_t *bus, uint target, bool pendok) -{ - int ret = BCME_OK; -#ifdef DHD_DEBUG - uint oldstate = bus->clkstate; -#endif /* DHD_DEBUG */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Early exit if we're already there */ - if (bus->clkstate == target) { - if (target == CLK_AVAIL) { - dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); - bus->activity = TRUE; -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; -#endif /* DHD_USE_IDLECOUNT */ - } - return ret; - } - - switch (target) { - case CLK_AVAIL: - /* Make sure SD clock is available */ - if (bus->clkstate == CLK_NONE) - dhdsdio_sdclk(bus, TRUE); - /* Now request HT Avail on the backplane */ - ret = dhdsdio_htclk(bus, TRUE, pendok); - if (ret == BCME_OK) { - dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); - bus->activity = TRUE; -#ifdef DHD_USE_IDLECOUNT - bus->idlecount = 0; -#endif /* DHD_USE_IDLECOUNT */ - } - break; - - case CLK_SDONLY: - /* Remove HT request, or bring up SD clock */ - if (bus->clkstate == CLK_NONE) - ret = dhdsdio_sdclk(bus, TRUE); - else if (bus->clkstate == CLK_AVAIL) - ret = dhdsdio_htclk(bus, FALSE, FALSE); - else - DHD_ERROR(("dhdsdio_clkctl: request for %d -> %d\n", - bus->clkstate, target)); - if (ret == BCME_OK) { - dhd_os_wd_timer(bus->dhd, dhd_watchdog_ms); - } - break; - - case CLK_NONE: - /* Make sure to remove HT request */ - if (bus->clkstate == CLK_AVAIL) - ret = dhdsdio_htclk(bus, FALSE, FALSE); - /* Now remove the SD clock */ - ret = dhdsdio_sdclk(bus, FALSE); -#ifdef DHD_DEBUG - if (dhd_console_ms == 0) -#endif /* DHD_DEBUG */ - dhd_os_wd_timer(bus->dhd, 0); - break; - } -#ifdef DHD_DEBUG - DHD_INFO(("dhdsdio_clkctl: %d -> %d\n", oldstate, bus->clkstate)); -#endif /* DHD_DEBUG */ - - return ret; -} - -static int -dhdsdio_bussleep(dhd_bus_t *bus, bool sleep) -{ - int err = 0; - bcmsdh_info_t *sdh = bus->sdh; - sdpcmd_regs_t *regs = bus->regs; - uint retries = 0; - - DHD_INFO(("dhdsdio_bussleep: request %s (currently %s)\n", - (sleep ? "SLEEP" : "WAKE"), - (bus->sleeping ? "SLEEP" : "WAKE"))); - - /* Done if we're already in the requested state */ - if (sleep == bus->sleeping) - return BCME_OK; - - /* Going to sleep: set the alarm and turn off the lights... */ - if (sleep) { - /* Don't sleep if something is pending */ - if (bus->dpc_sched || bus->rxskip || pktq_len(&bus->txq) || bus->readframes) - return BCME_BUSY; - - - if (!SLPAUTO_ENAB(bus)) { - /* Disable SDIO interrupts (no longer interested) */ - bcmsdh_intr_disable(bus->sdh); - - /* Make sure the controller has the bus up */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Tell device to start using OOB wakeup */ - W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); - if (retries > retry_limit) - DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); - - /* Turn off our contribution to the HT clock request */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); - - /* Isolate the bus */ - if (bus->sih->chip != BCM4329_CHIP_ID && - bus->sih->chip != BCM4319_CHIP_ID) { - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, - SBSDIO_DEVCTL_PADS_ISO, NULL); - } - } else { - /* Leave interrupts enabled since device can exit sleep and - * interrupt host - */ - err = dhdsdio_clk_devsleep_iovar(bus, TRUE /* sleep */); - } - - /* Change state */ - bus->sleeping = TRUE; - - } else { - /* Waking up: bus power up is ok, set local state */ - - if (!SLPAUTO_ENAB(bus)) { - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, &err); - - /* Force pad isolation off if possible (in case power never toggled) */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, 0, NULL); - - - /* Make sure the controller has the bus up */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Send misc interrupt to indicate OOB not needed */ - W_SDREG(0, ®s->tosbmailboxdata, retries); - if (retries <= retry_limit) - W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); - - if (retries > retry_limit) - DHD_ERROR(("CANNOT SIGNAL CHIP TO CLEAR OOB!!\n")); - - /* Make sure we have SD bus access */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - - /* Enable interrupts again */ - if (bus->intr && (bus->dhd->busstate == DHD_BUS_DATA)) { - bus->intdis = FALSE; - bcmsdh_intr_enable(bus->sdh); - } - } else { - err = dhdsdio_clk_devsleep_iovar(bus, FALSE /* wake */); - } - - if (err == 0) { - /* Change state */ - bus->sleeping = FALSE; - } - } - - return err; -} - -#ifdef VSDB_DYNAMIC_F2_BLKSIZE -int -dhdsdio_func_blocksize(dhd_pub_t *dhd, int function_num, int block_size) -{ - int func_blk_size = function_num; - int bcmerr = 0; - int result; - - bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size, sizeof(int), &result, sizeof(int), 0); - - if (bcmerr != BCME_OK) { - DHD_ERROR(("%s: Get F%d Block size error\n", __FUNCTION__, function_num)); - return BCME_ERROR; - } - - if (result != block_size) { - - DHD_ERROR(("%s: F%d Block size set from %d to %d\n", __FUNCTION__, function_num, result, block_size)); - - func_blk_size = function_num << 16 | block_size ; - bcmerr = dhd_bus_iovar_op(dhd, "sd_blocksize", &func_blk_size, sizeof(int32), &result, sizeof(int32), 1); - - if (bcmerr != BCME_OK) { - DHD_ERROR(("%s: Set F2 Block size error\n", __FUNCTION__)); - return BCME_ERROR; - } - } - - return BCME_OK; - -} -#endif -#if defined(OOB_INTR_ONLY) -void -dhd_enable_oob_intr(struct dhd_bus *bus, bool enable) -{ -#if defined(HW_OOB) - bcmsdh_enable_hw_oob_intr(bus->sdh, enable); -#else - sdpcmd_regs_t *regs = bus->regs; - uint retries = 0; - - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - if (enable == TRUE) { - - /* Tell device to start using OOB wakeup */ - W_SDREG(SMB_USE_OOB, ®s->tosbmailbox, retries); - if (retries > retry_limit) - DHD_ERROR(("CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n")); - - } else { - /* Send misc interrupt to indicate OOB not needed */ - W_SDREG(0, ®s->tosbmailboxdata, retries); - if (retries <= retry_limit) - W_SDREG(SMB_DEV_INT, ®s->tosbmailbox, retries); - } - - /* Turn off our contribution to the HT clock request */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); -#endif /* !defined(HW_OOB) */ -} -#endif /* defined(OOB_INTR_ONLY) */ - -/* Writes a HW/SW header into the packet and sends it. */ -/* Assumes: (a) header space already there, (b) caller holds lock */ -static int -dhdsdio_txpkt(dhd_bus_t *bus, void *pkt, uint chan, bool free_pkt) -{ - int ret; - osl_t *osh; - uint8 *frame; - uint16 len, pad1 = 0; - uint32 swheader; - uint retries = 0; - bcmsdh_info_t *sdh; - void *new; - int i; -#ifdef WLMEDIA_HTSF - char *p; - htsfts_t *htsf_ts; -#endif - - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - sdh = bus->sdh; - osh = bus->dhd->osh; - - if (bus->dhd->dongle_reset) { - ret = BCME_NOTREADY; - goto done; - } - - frame = (uint8*)PKTDATA(osh, pkt); - -#ifdef WLMEDIA_HTSF - if (PKTLEN(osh, pkt) >= 100) { - p = PKTDATA(osh, pkt); - htsf_ts = (htsfts_t*) (p + HTSF_HOSTOFFSET + 12); - if (htsf_ts->magic == HTSFMAGIC) { - htsf_ts->c20 = get_cycles(); - htsf_ts->t20 = dhd_get_htsf(bus->dhd->info, 0); - } - } -#endif /* WLMEDIA_HTSF */ - - /* Add alignment padding, allocate new packet if needed */ - if ((pad1 = ((uintptr)frame % DHD_SDALIGN))) { - if (PKTHEADROOM(osh, pkt) < pad1) { - DHD_INFO(("%s: insufficient headroom %d for %d pad1\n", - __FUNCTION__, (int)PKTHEADROOM(osh, pkt), pad1)); - bus->dhd->tx_realloc++; - new = PKTGET(osh, (PKTLEN(osh, pkt) + DHD_SDALIGN), TRUE); - if (!new) { - DHD_ERROR(("%s: couldn't allocate new %d-byte packet\n", - __FUNCTION__, PKTLEN(osh, pkt) + DHD_SDALIGN)); - ret = BCME_NOMEM; - goto done; - } - - PKTALIGN(osh, new, PKTLEN(osh, pkt), DHD_SDALIGN); - bcopy(PKTDATA(osh, pkt), PKTDATA(osh, new), PKTLEN(osh, pkt)); - if (free_pkt) - PKTFREE(osh, pkt, TRUE); - /* free the pkt if canned one is not used */ - free_pkt = TRUE; - pkt = new; - frame = (uint8*)PKTDATA(osh, pkt); - ASSERT(((uintptr)frame % DHD_SDALIGN) == 0); - pad1 = 0; - } else { -#ifdef CUSTOMER_HW_SAMSUNG - /* Adjust pad value to fix firmware crash problems - * because of odd start address of the frame - * (CSP#455126) - */ - if ((int)frame & 1) - pad1--; -#endif - PKTPUSH(osh, pkt, pad1); - frame = (uint8*)PKTDATA(osh, pkt); - - ASSERT((pad1 + SDPCM_HDRLEN) <= (int) PKTLEN(osh, pkt)); - bzero(frame, pad1 + SDPCM_HDRLEN); - } - } - ASSERT(pad1 < DHD_SDALIGN); - - /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ - len = (uint16)PKTLEN(osh, pkt); - *(uint16*)frame = htol16(len); - *(((uint16*)frame) + 1) = htol16(~len); - - /* Software tag: channel, sequence number, data offset */ - swheader = ((chan << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) | bus->tx_seq | - (((pad1 + SDPCM_HDRLEN) << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); - htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); - htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); - -#ifdef DHD_DEBUG - if (PKTPRIO(pkt) < ARRAYSIZE(tx_packets)) { - tx_packets[PKTPRIO(pkt)]++; - } - if (DHD_BYTES_ON() && - (((DHD_CTL_ON() && (chan == SDPCM_CONTROL_CHANNEL)) || - (DHD_DATA_ON() && (chan != SDPCM_CONTROL_CHANNEL))))) { - prhex("Tx Frame", frame, len); - } else if (DHD_HDRS_ON()) { - prhex("TxHdr", frame, MIN(len, 16)); - } -#endif - - /* Raise len to next SDIO block to eliminate tail command */ - if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { - uint16 pad2 = bus->blocksize - (len % bus->blocksize); - if ((pad2 <= bus->roundup) && (pad2 < bus->blocksize)) -#ifdef NOTUSED - if (pad2 <= PKTTAILROOM(osh, pkt)) -#endif /* NOTUSED */ - len += pad2; - } else if (len % DHD_SDALIGN) { - len += DHD_SDALIGN - (len % DHD_SDALIGN); - } - - /* Some controllers have trouble with odd bytes -- round to even */ - if (forcealign && (len & (ALIGNMENT - 1))) { -#ifdef NOTUSED - if (PKTTAILROOM(osh, pkt)) -#endif - len = ROUNDUP(len, ALIGNMENT); -#ifdef NOTUSED - else - DHD_ERROR(("%s: sending unrounded %d-byte packet\n", __FUNCTION__, len)); -#endif - } - - do { - ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - frame, len, pkt, NULL, NULL); - bus->f2txdata++; - ASSERT(ret != BCME_PENDING); - - if (ret == BCME_NODEVICE) { - DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); - } else if (ret < 0) { - /* On failure, abort the command and terminate the frame */ - DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n", - __FUNCTION__, ret)); - bus->tx_sderrs++; - - bcmsdh_abort(sdh, SDIO_FUNC_2); - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, - SFC_WF_TERM, NULL); - bus->f1regdata++; - - for (i = 0; i < 3; i++) { - uint8 hi, lo; - hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCHI, NULL); - lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCLO, NULL); - bus->f1regdata += 2; - if ((hi == 0) && (lo == 0)) - break; - } - } - if (ret == 0) { - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - } - } while ((ret < 0) && retrydata && retries++ < TXRETRIES); - -done: - /* restore pkt buffer pointer before calling tx complete routine */ - PKTPULL(osh, pkt, SDPCM_HDRLEN + pad1); -#ifdef PROP_TXSTATUS - if (bus->dhd->wlfc_state) { - dhd_os_sdunlock(bus->dhd); - dhd_wlfc_txcomplete(bus->dhd, pkt, ret == 0); - dhd_os_sdlock(bus->dhd); - } else { -#endif /* PROP_TXSTATUS */ - dhd_txcomplete(bus->dhd, pkt, ret != 0); - if (free_pkt) - PKTFREE(osh, pkt, TRUE); - -#ifdef PROP_TXSTATUS - } -#endif - return ret; -} - -int -dhd_bus_txdata(struct dhd_bus *bus, void *pkt) -{ - int ret = BCME_ERROR; - osl_t *osh; - uint datalen, prec; -#ifdef DHD_TX_DUMP - uint8 *dump_data; - uint16 protocol; -#ifdef DHD_TX_FULL_DUMP - int i; -#endif /* DHD_TX_FULL_DUMP */ -#endif /* DHD_TX_DUMP */ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - osh = bus->dhd->osh; - datalen = PKTLEN(osh, pkt); - -#ifdef SDTEST - /* Push the test header if doing loopback */ - if (bus->ext_loop) { - uint8* data; - PKTPUSH(osh, pkt, SDPCM_TEST_HDRLEN); - data = PKTDATA(osh, pkt); - *data++ = SDPCM_TEST_ECHOREQ; - *data++ = (uint8)bus->loopid++; - *data++ = (datalen >> 0); - *data++ = (datalen >> 8); - datalen += SDPCM_TEST_HDRLEN; - } -#endif /* SDTEST */ -#ifdef DHD_TX_DUMP - dump_data = PKTDATA(osh, pkt); - dump_data += 4; /* skip 4 bytes header */ - protocol = (dump_data[12] << 8) | dump_data[13]; -#ifdef DHD_TX_FULL_DUMP - DHD_ERROR(("TX DUMP\n")); - - for (i = 0; i < (datalen - 4); i++) { - DHD_ERROR(("%02X ", dump_data[i])); - if ((i & 15) == 15) - printk("\n"); - } - DHD_ERROR(("\n")); - -#endif /* DHD_TX_FULL_DUMP */ - if (protocol == ETHER_TYPE_802_1X) { - DHD_ERROR(("ETHER_TYPE_802_1X: ver %d, type %d, replay %d\n", - dump_data[14], dump_data[15], dump_data[30])); - } -#endif /* DHD_TX_DUMP */ - - /* Add space for the header */ - PKTPUSH(osh, pkt, SDPCM_HDRLEN); - ASSERT(ISALIGNED((uintptr)PKTDATA(osh, pkt), 2)); - - prec = PRIO2PREC((PKTPRIO(pkt) & PRIOMASK)); -#ifndef DHDTHREAD - /* Lock: we're about to use shared data/code (and SDIO) */ - dhd_os_sdlock(bus->dhd); -#endif /* DHDTHREAD */ - - /* Check for existing queue, current flow-control, pending event, or pending clock */ - if (dhd_deferred_tx || bus->fcstate || pktq_len(&bus->txq) || bus->dpc_sched || - (!DATAOK(bus)) || (bus->flowcontrol & NBITVAL(prec)) || - (bus->clkstate != CLK_AVAIL)) { - DHD_TRACE(("%s: deferring pktq len %d\n", __FUNCTION__, - pktq_len(&bus->txq))); - bus->fcqueued++; - - /* Priority based enq */ - dhd_os_sdlock_txq(bus->dhd); - if (dhd_prec_enq(bus->dhd, &bus->txq, pkt, prec) == FALSE) { - PKTPULL(osh, pkt, SDPCM_HDRLEN); -#ifndef DHDTHREAD - /* Need to also release txqlock before releasing sdlock. - * This thread still has txqlock and releases sdlock. - * Deadlock happens when dpc() grabs sdlock first then - * attempts to grab txqlock. - */ - dhd_os_sdunlock_txq(bus->dhd); - dhd_os_sdunlock(bus->dhd); -#endif -#ifdef PROP_TXSTATUS - if (bus->dhd->wlfc_state) - dhd_wlfc_txcomplete(bus->dhd, pkt, FALSE); - else -#endif - dhd_txcomplete(bus->dhd, pkt, FALSE); -#ifndef DHDTHREAD - dhd_os_sdlock(bus->dhd); - dhd_os_sdlock_txq(bus->dhd); -#endif -#ifdef PROP_TXSTATUS - /* let the caller decide whether to free the packet */ - if (!bus->dhd->wlfc_state) -#endif - PKTFREE(osh, pkt, TRUE); - ret = BCME_NORESOURCE; - } - else - ret = BCME_OK; - dhd_os_sdunlock_txq(bus->dhd); - - if ((pktq_len(&bus->txq) >= FCHI) && dhd_doflow) - dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); - -#ifdef DHD_DEBUG - if (pktq_plen(&bus->txq, prec) > qcount[prec]) - qcount[prec] = pktq_plen(&bus->txq, prec); -#endif - /* Schedule DPC if needed to send queued packet(s) */ - if (dhd_deferred_tx && !bus->dpc_sched) { - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - } - } else { -#ifdef DHDTHREAD - /* Lock: we're about to use shared data/code (and SDIO) */ - dhd_os_sdlock(bus->dhd); -#endif /* DHDTHREAD */ - - /* Otherwise, send it now */ - BUS_WAKE(bus); - /* Make sure back plane ht clk is on, no pending allowed */ - dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); -#ifndef SDTEST - ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE); -#else - ret = dhdsdio_txpkt(bus, pkt, - (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE); -#endif - if (ret) - bus->dhd->tx_errors++; - else - bus->dhd->dstats.tx_bytes += datalen; - - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - -#ifdef DHDTHREAD - dhd_os_sdunlock(bus->dhd); -#endif /* DHDTHREAD */ - } - -#ifndef DHDTHREAD - dhd_os_sdunlock(bus->dhd); -#endif /* DHDTHREAD */ - - return ret; -} - -static uint -dhdsdio_sendfromq(dhd_bus_t *bus, uint maxframes) -{ - void *pkt; - uint32 intstatus = 0; - uint retries = 0; - int ret = 0, prec_out; - uint cnt = 0; - uint datalen; - uint8 tx_prec_map; - - dhd_pub_t *dhd = bus->dhd; - sdpcmd_regs_t *regs = bus->regs; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - return BCME_NODEVICE; - } - - tx_prec_map = ~bus->flowcontrol; - - /* Send frames until the limit or some other event */ - for (cnt = 0; (cnt < maxframes) && DATAOK(bus); cnt++) { - dhd_os_sdlock_txq(bus->dhd); - if ((pkt = pktq_mdeq(&bus->txq, tx_prec_map, &prec_out)) == NULL) { - dhd_os_sdunlock_txq(bus->dhd); - break; - } - dhd_os_sdunlock_txq(bus->dhd); - datalen = PKTLEN(bus->dhd->osh, pkt) - SDPCM_HDRLEN; - -#ifndef SDTEST - ret = dhdsdio_txpkt(bus, pkt, SDPCM_DATA_CHANNEL, TRUE); -#else - ret = dhdsdio_txpkt(bus, pkt, - (bus->ext_loop ? SDPCM_TEST_CHANNEL : SDPCM_DATA_CHANNEL), TRUE); -#endif - if (ret) - bus->dhd->tx_errors++; - else - bus->dhd->dstats.tx_bytes += datalen; - - /* In poll mode, need to check for other events */ - if (!bus->intr && cnt) - { - /* Check device status, signal pending interrupt */ - R_SDREG(intstatus, ®s->intstatus, retries); - bus->f2txdata++; - if (bcmsdh_regfail(bus->sdh)) - break; - if (intstatus & bus->hostintmask) - bus->ipend = TRUE; - } - } - - /* Deflow-control stack if needed */ - if (dhd_doflow && dhd->up && (dhd->busstate == DHD_BUS_DATA) && - dhd->txoff && (pktq_len(&bus->txq) < FCLOW)) - dhd_txflowcontrol(dhd, ALL_INTERFACES, OFF); - - return cnt; -} - -int -dhd_bus_txctl(struct dhd_bus *bus, uchar *msg, uint msglen) -{ - uint8 *frame; - uint16 len; - uint32 swheader; - uint retries = 0; - bcmsdh_info_t *sdh = bus->sdh; - uint8 doff = 0; - int ret = -1; - int i; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd->dongle_reset) - return -EIO; - - /* Back the pointer to make a room for bus header */ - frame = msg - SDPCM_HDRLEN; - len = (msglen += SDPCM_HDRLEN); - - /* Add alignment padding (optional for ctl frames) */ - if (dhd_alignctl) { - if ((doff = ((uintptr)frame % DHD_SDALIGN))) { - frame -= doff; - len += doff; - msglen += doff; - bzero(frame, doff + SDPCM_HDRLEN); - } - ASSERT(doff < DHD_SDALIGN); - } - doff += SDPCM_HDRLEN; - - /* Round send length to next SDIO block */ - if (bus->roundup && bus->blocksize && (len > bus->blocksize)) { - uint16 pad = bus->blocksize - (len % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize)) - len += pad; - } else if (len % DHD_SDALIGN) { - len += DHD_SDALIGN - (len % DHD_SDALIGN); - } - - /* Satisfy length-alignment requirements */ - if (forcealign && (len & (ALIGNMENT - 1))) - len = ROUNDUP(len, ALIGNMENT); - - ASSERT(ISALIGNED((uintptr)frame, 2)); - - - /* Need to lock here to protect txseq and SDIO tx calls */ - dhd_os_sdlock(bus->dhd); - - BUS_WAKE(bus); - - /* Make sure backplane clock is on */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */ - *(uint16*)frame = htol16((uint16)msglen); - *(((uint16*)frame) + 1) = htol16(~msglen); - - /* Software tag: channel, sequence number, data offset */ - swheader = ((SDPCM_CONTROL_CHANNEL << SDPCM_CHANNEL_SHIFT) & SDPCM_CHANNEL_MASK) - | bus->tx_seq | ((doff << SDPCM_DOFFSET_SHIFT) & SDPCM_DOFFSET_MASK); - htol32_ua_store(swheader, frame + SDPCM_FRAMETAG_LEN); - htol32_ua_store(0, frame + SDPCM_FRAMETAG_LEN + sizeof(swheader)); - - if (!TXCTLOK(bus)) { - DHD_INFO(("%s: No bus credit bus->tx_max %d, bus->tx_seq %d\n", - __FUNCTION__, bus->tx_max, bus->tx_seq)); - bus->ctrl_frame_stat = TRUE; - /* Send from dpc */ - bus->ctrl_frame_buf = frame; - bus->ctrl_frame_len = len; - if(!bus->dpc_sched) { - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - } - if (bus->ctrl_frame_stat) { - dhd_wait_for_event(bus->dhd, &bus->ctrl_frame_stat); - } - - if (bus->ctrl_frame_stat == FALSE) { - DHD_INFO(("%s: ctrl_frame_stat == FALSE\n", __FUNCTION__)); - ret = 0; - } else { - bus->dhd->txcnt_timeout++; - if (!bus->dhd->hang_was_sent) - DHD_ERROR(("%s: ctrl_frame_stat == TRUE txcnt_timeout=%d\n", - __FUNCTION__, bus->dhd->txcnt_timeout)); - ret = -1; - bus->ctrl_frame_stat = FALSE; - goto done; - } - } - - bus->dhd->txcnt_timeout = 0; - - if (ret == -1) { -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_CTL_ON()) { - prhex("Tx Frame", frame, len); - } else if (DHD_HDRS_ON()) { - prhex("TxHdr", frame, MIN(len, 16)); - } -#endif - - do { - ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - frame, len, NULL, NULL, NULL); - ASSERT(ret != BCME_PENDING); - - if (ret == BCME_NODEVICE) { - DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); - } else if (ret < 0) { - /* On failure, abort the command and terminate the frame */ - DHD_ERROR(("%s: sdio error %d, abort command and terminate frame.\n", - __FUNCTION__, ret)); - bus->tx_sderrs++; - - bcmsdh_abort(sdh, SDIO_FUNC_2); - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, - SFC_WF_TERM, NULL); - bus->f1regdata++; - - for (i = 0; i < 3; i++) { - uint8 hi, lo; - hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCHI, NULL); - lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCLO, NULL); - bus->f1regdata += 2; - if ((hi == 0) && (lo == 0)) - break; - } - } - if (ret == 0) { - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - } - } while ((ret < 0) && retries++ < TXRETRIES); - } - -done: - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - - if (ret) - bus->dhd->tx_ctlerrs++; - else - bus->dhd->tx_ctlpkts++; - - if (bus->dhd->txcnt_timeout >= MAX_CNTL_TIMEOUT) - return -ETIMEDOUT; - - return ret ? -EIO : 0; -} - -int -dhd_bus_rxctl(struct dhd_bus *bus, uchar *msg, uint msglen) -{ - int timeleft; - uint rxlen = 0; - bool pending; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd->dongle_reset) - return -EIO; - - /* Wait until control frame is available */ - timeleft = dhd_os_ioctl_resp_wait(bus->dhd, &bus->rxlen, &pending); - - dhd_os_sdlock(bus->dhd); - rxlen = bus->rxlen; - bcopy(bus->rxctl, msg, MIN(msglen, rxlen)); - bus->rxlen = 0; - dhd_os_sdunlock(bus->dhd); - - if (rxlen) { - DHD_CTL(("%s: resumed on rxctl frame, got %d expected %d\n", - __FUNCTION__, rxlen, msglen)); - } else if (timeleft == 0) { - u32 status; - int retry = 0; - R_SDREG(status, &bus->regs->intstatus, retry); - DHD_ERROR(("%s: resumed on timeout, INT status=0x%08X\n", __FUNCTION__, status)); -#ifdef DHD_DEBUG -#if !defined(CUSTOMER_HW_SAMSUNG) -#error need debug message if dongle trap occured - if (!SLPAUTO_ENAB(bus)) { -#endif - dhd_os_sdlock(bus->dhd); - dhdsdio_checkdied(bus, NULL, 0); - dhd_os_sdunlock(bus->dhd); -#if !defined(CUSTOMER_HW_SAMSUNG) - } -#endif -#endif /* DHD_DEBUG */ - } else if (pending == TRUE) { - DHD_ERROR(("%s: canceled\n", __FUNCTION__)); - return -ERESTARTSYS; - } else { - DHD_ERROR(("%s: resumed for unknown reason?\n", __FUNCTION__)); -#ifdef DHD_DEBUG - dhd_os_sdlock(bus->dhd); - dhdsdio_checkdied(bus, NULL, 0); - dhd_os_sdunlock(bus->dhd); -#endif /* DHD_DEBUG */ - } - if (timeleft == 0) { - bus->dhd->rxcnt_timeout++; - DHD_ERROR(("%s: rxcnt_timeout=%d\n", __FUNCTION__, bus->dhd->rxcnt_timeout)); - } - else - bus->dhd->rxcnt_timeout = 0; - - if (rxlen) - bus->dhd->rx_ctlpkts++; - else - bus->dhd->rx_ctlerrs++; - - if (bus->dhd->rxcnt_timeout >= MAX_CNTL_TIMEOUT) - return -ETIMEDOUT; - - if (bus->dhd->dongle_trap_occured) - return -EREMOTEIO; - - return rxlen ? (int)rxlen : -EIO; -} - -/* IOVar table */ -enum { - IOV_INTR = 1, - IOV_POLLRATE, - IOV_SDREG, - IOV_SBREG, - IOV_SDCIS, - IOV_MEMBYTES, - IOV_MEMSIZE, -#ifdef DHD_DEBUG - IOV_CHECKDIED, - IOV_SERIALCONS, -#endif /* DHD_DEBUG */ - IOV_SET_DOWNLOAD_STATE, - IOV_SOCRAM_STATE, - IOV_FORCEEVEN, - IOV_SDIOD_DRIVE, - IOV_READAHEAD, - IOV_SDRXCHAIN, - IOV_ALIGNCTL, - IOV_SDALIGN, - IOV_DEVRESET, - IOV_CPU, -#ifdef SDTEST - IOV_PKTGEN, - IOV_EXTLOOP, -#endif /* SDTEST */ - IOV_SPROM, - IOV_TXBOUND, - IOV_RXBOUND, - IOV_TXMINMAX, - IOV_IDLETIME, - IOV_IDLECLOCK, - IOV_SD1IDLE, - IOV_SLEEP, - IOV_DONGLEISOLATION, - IOV_KSO, - IOV_DEVSLEEP, - IOV_DEVCAP, - IOV_VARS, -#ifdef SOFTAP - IOV_FWPATH -#endif -}; - -const bcm_iovar_t dhdsdio_iovars[] = { - {"intr", IOV_INTR, 0, IOVT_BOOL, 0 }, - {"sleep", IOV_SLEEP, 0, IOVT_BOOL, 0 }, - {"pollrate", IOV_POLLRATE, 0, IOVT_UINT32, 0 }, - {"idletime", IOV_IDLETIME, 0, IOVT_INT32, 0 }, - {"idleclock", IOV_IDLECLOCK, 0, IOVT_INT32, 0 }, - {"sd1idle", IOV_SD1IDLE, 0, IOVT_BOOL, 0 }, - {"membytes", IOV_MEMBYTES, 0, IOVT_BUFFER, 2 * sizeof(int) }, - {"memsize", IOV_MEMSIZE, 0, IOVT_UINT32, 0 }, - {"dwnldstate", IOV_SET_DOWNLOAD_STATE, 0, IOVT_BOOL, 0 }, - {"socram_state", IOV_SOCRAM_STATE, 0, IOVT_BOOL, 0 }, - {"vars", IOV_VARS, 0, IOVT_BUFFER, 0 }, - {"sdiod_drive", IOV_SDIOD_DRIVE, 0, IOVT_UINT32, 0 }, - {"readahead", IOV_READAHEAD, 0, IOVT_BOOL, 0 }, - {"sdrxchain", IOV_SDRXCHAIN, 0, IOVT_BOOL, 0 }, - {"alignctl", IOV_ALIGNCTL, 0, IOVT_BOOL, 0 }, - {"sdalign", IOV_SDALIGN, 0, IOVT_BOOL, 0 }, - {"devreset", IOV_DEVRESET, 0, IOVT_BOOL, 0 }, -#ifdef DHD_DEBUG - {"sdreg", IOV_SDREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sbreg", IOV_SBREG, 0, IOVT_BUFFER, sizeof(sdreg_t) }, - {"sd_cis", IOV_SDCIS, 0, IOVT_BUFFER, DHD_IOCTL_MAXLEN }, - {"forcealign", IOV_FORCEEVEN, 0, IOVT_BOOL, 0 }, - {"txbound", IOV_TXBOUND, 0, IOVT_UINT32, 0 }, - {"rxbound", IOV_RXBOUND, 0, IOVT_UINT32, 0 }, - {"txminmax", IOV_TXMINMAX, 0, IOVT_UINT32, 0 }, - {"cpu", IOV_CPU, 0, IOVT_BOOL, 0 }, -#ifdef DHD_DEBUG - {"checkdied", IOV_CHECKDIED, 0, IOVT_BUFFER, 0 }, - {"serial", IOV_SERIALCONS, 0, IOVT_UINT32, 0 }, -#endif /* DHD_DEBUG */ -#endif /* DHD_DEBUG */ -#ifdef SDTEST - {"extloop", IOV_EXTLOOP, 0, IOVT_BOOL, 0 }, - {"pktgen", IOV_PKTGEN, 0, IOVT_BUFFER, sizeof(dhd_pktgen_t) }, -#endif /* SDTEST */ - {"devcap", IOV_DEVCAP, 0, IOVT_UINT32, 0 }, - {"dngl_isolation", IOV_DONGLEISOLATION, 0, IOVT_UINT32, 0 }, - {"kso", IOV_KSO, 0, IOVT_UINT32, 0 }, - {"devsleep", IOV_DEVSLEEP, 0, IOVT_UINT32, 0 }, -#ifdef SOFTAP - {"fwpath", IOV_FWPATH, 0, IOVT_BUFFER, 0 }, -#endif - {NULL, 0, 0, 0, 0 } -}; - -static void -dhd_dump_pct(struct bcmstrbuf *strbuf, char *desc, uint num, uint div) -{ - uint q1, q2; - - if (!div) { - bcm_bprintf(strbuf, "%s N/A", desc); - } else { - q1 = num / div; - q2 = (100 * (num - (q1 * div))) / div; - bcm_bprintf(strbuf, "%s %d.%02d", desc, q1, q2); - } -} - -void -dhd_bus_dump(dhd_pub_t *dhdp, struct bcmstrbuf *strbuf) -{ - dhd_bus_t *bus = dhdp->bus; - - bcm_bprintf(strbuf, "Bus SDIO structure:\n"); - bcm_bprintf(strbuf, "hostintmask 0x%08x intstatus 0x%08x sdpcm_ver %d\n", - bus->hostintmask, bus->intstatus, bus->sdpcm_ver); - bcm_bprintf(strbuf, "fcstate %d qlen %d tx_seq %d, max %d, rxskip %d rxlen %d rx_seq %d\n", - bus->fcstate, pktq_len(&bus->txq), bus->tx_seq, bus->tx_max, bus->rxskip, - bus->rxlen, bus->rx_seq); - bcm_bprintf(strbuf, "intr %d intrcount %d lastintrs %d spurious %d\n", - bus->intr, bus->intrcount, bus->lastintrs, bus->spurious); - bcm_bprintf(strbuf, "pollrate %d pollcnt %d regfails %d\n", - bus->pollrate, bus->pollcnt, bus->regfails); - - bcm_bprintf(strbuf, "\nAdditional counters:\n"); - bcm_bprintf(strbuf, "tx_sderrs %d fcqueued %d rxrtx %d rx_toolong %d rxc_errors %d\n", - bus->tx_sderrs, bus->fcqueued, bus->rxrtx, bus->rx_toolong, - bus->rxc_errors); - bcm_bprintf(strbuf, "rx_hdrfail %d badhdr %d badseq %d\n", - bus->rx_hdrfail, bus->rx_badhdr, bus->rx_badseq); - bcm_bprintf(strbuf, "fc_rcvd %d, fc_xoff %d, fc_xon %d\n", - bus->fc_rcvd, bus->fc_xoff, bus->fc_xon); - bcm_bprintf(strbuf, "rxglomfail %d, rxglomframes %d, rxglompkts %d\n", - bus->rxglomfail, bus->rxglomframes, bus->rxglompkts); - bcm_bprintf(strbuf, "f2rx (hdrs/data) %d (%d/%d), f2tx %d f1regs %d\n", - (bus->f2rxhdrs + bus->f2rxdata), bus->f2rxhdrs, bus->f2rxdata, - bus->f2txdata, bus->f1regdata); - { - dhd_dump_pct(strbuf, "\nRx: pkts/f2rd", bus->dhd->rx_packets, - (bus->f2rxhdrs + bus->f2rxdata)); - dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->rx_packets, bus->f1regdata); - dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->rx_packets, - (bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); - dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->rx_packets, bus->intrcount); - bcm_bprintf(strbuf, "\n"); - - dhd_dump_pct(strbuf, "Rx: glom pct", (100 * bus->rxglompkts), - bus->dhd->rx_packets); - dhd_dump_pct(strbuf, ", pkts/glom", bus->rxglompkts, bus->rxglomframes); - bcm_bprintf(strbuf, "\n"); - - dhd_dump_pct(strbuf, "Tx: pkts/f2wr", bus->dhd->tx_packets, bus->f2txdata); - dhd_dump_pct(strbuf, ", pkts/f1sd", bus->dhd->tx_packets, bus->f1regdata); - dhd_dump_pct(strbuf, ", pkts/sd", bus->dhd->tx_packets, - (bus->f2txdata + bus->f1regdata)); - dhd_dump_pct(strbuf, ", pkts/int", bus->dhd->tx_packets, bus->intrcount); - bcm_bprintf(strbuf, "\n"); - - dhd_dump_pct(strbuf, "Total: pkts/f2rw", - (bus->dhd->tx_packets + bus->dhd->rx_packets), - (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata)); - dhd_dump_pct(strbuf, ", pkts/f1sd", - (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->f1regdata); - dhd_dump_pct(strbuf, ", pkts/sd", - (bus->dhd->tx_packets + bus->dhd->rx_packets), - (bus->f2txdata + bus->f2rxhdrs + bus->f2rxdata + bus->f1regdata)); - dhd_dump_pct(strbuf, ", pkts/int", - (bus->dhd->tx_packets + bus->dhd->rx_packets), bus->intrcount); - bcm_bprintf(strbuf, "\n\n"); - } - -#ifdef SDTEST - if (bus->pktgen_count) { - bcm_bprintf(strbuf, "pktgen config and count:\n"); - bcm_bprintf(strbuf, "freq %d count %d print %d total %d min %d len %d\n", - bus->pktgen_freq, bus->pktgen_count, bus->pktgen_print, - bus->pktgen_total, bus->pktgen_minlen, bus->pktgen_maxlen); - bcm_bprintf(strbuf, "send attempts %d rcvd %d fail %d\n", - bus->pktgen_sent, bus->pktgen_rcvd, bus->pktgen_fail); - } -#endif /* SDTEST */ -#ifdef DHD_DEBUG - bcm_bprintf(strbuf, "dpc_sched %d host interrupt%spending\n", - bus->dpc_sched, (bcmsdh_intr_pending(bus->sdh) ? " " : " not ")); - bcm_bprintf(strbuf, "blocksize %d roundup %d\n", bus->blocksize, bus->roundup); -#endif /* DHD_DEBUG */ - bcm_bprintf(strbuf, "clkstate %d activity %d idletime %d idlecount %d sleeping %d\n", - bus->clkstate, bus->activity, bus->idletime, bus->idlecount, bus->sleeping); -} - -void -dhd_bus_clearcounts(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus = (dhd_bus_t *)dhdp->bus; - - bus->intrcount = bus->lastintrs = bus->spurious = bus->regfails = 0; - bus->rxrtx = bus->rx_toolong = bus->rxc_errors = 0; - bus->rx_hdrfail = bus->rx_badhdr = bus->rx_badseq = 0; - bus->tx_sderrs = bus->fc_rcvd = bus->fc_xoff = bus->fc_xon = 0; - bus->rxglomfail = bus->rxglomframes = bus->rxglompkts = 0; - bus->f2rxhdrs = bus->f2rxdata = bus->f2txdata = bus->f1regdata = 0; -} - -#ifdef SDTEST -static int -dhdsdio_pktgen_get(dhd_bus_t *bus, uint8 *arg) -{ - dhd_pktgen_t pktgen; - - pktgen.version = DHD_PKTGEN_VERSION; - pktgen.freq = bus->pktgen_freq; - pktgen.count = bus->pktgen_count; - pktgen.print = bus->pktgen_print; - pktgen.total = bus->pktgen_total; - pktgen.minlen = bus->pktgen_minlen; - pktgen.maxlen = bus->pktgen_maxlen; - pktgen.numsent = bus->pktgen_sent; - pktgen.numrcvd = bus->pktgen_rcvd; - pktgen.numfail = bus->pktgen_fail; - pktgen.mode = bus->pktgen_mode; - pktgen.stop = bus->pktgen_stop; - - bcopy(&pktgen, arg, sizeof(pktgen)); - - return 0; -} - -static int -dhdsdio_pktgen_set(dhd_bus_t *bus, uint8 *arg) -{ - dhd_pktgen_t pktgen; - uint oldcnt, oldmode; - - bcopy(arg, &pktgen, sizeof(pktgen)); - if (pktgen.version != DHD_PKTGEN_VERSION) - return BCME_BADARG; - - oldcnt = bus->pktgen_count; - oldmode = bus->pktgen_mode; - - bus->pktgen_freq = pktgen.freq; - bus->pktgen_count = pktgen.count; - bus->pktgen_print = pktgen.print; - bus->pktgen_total = pktgen.total; - bus->pktgen_minlen = pktgen.minlen; - bus->pktgen_maxlen = pktgen.maxlen; - bus->pktgen_mode = pktgen.mode; - bus->pktgen_stop = pktgen.stop; - - bus->pktgen_tick = bus->pktgen_ptick = 0; - bus->pktgen_len = MAX(bus->pktgen_len, bus->pktgen_minlen); - bus->pktgen_len = MIN(bus->pktgen_len, bus->pktgen_maxlen); - - /* Clear counts for a new pktgen (mode change, or was stopped) */ - if (bus->pktgen_count && (!oldcnt || oldmode != bus->pktgen_mode)) - bus->pktgen_sent = bus->pktgen_rcvd = bus->pktgen_fail = 0; - - return 0; -} -#endif /* SDTEST */ - -static void -dhdsdio_devram_remap(dhd_bus_t *bus, bool val) -{ - uint8 enable, protect, remap; - - si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); - remap = val ? TRUE : FALSE; - si_socdevram(bus->sih, TRUE, &enable, &protect, &remap); -} - -static int -dhdsdio_membytes(dhd_bus_t *bus, bool write, uint32 address, uint8 *data, uint size) -{ - int bcmerror = 0; - uint32 sdaddr; - uint dsize; - - /* In remap mode, adjust address beyond socram and redirect - * to devram at SOCDEVRAM_BP_ADDR since remap address > orig_ramsize - * is not backplane accessible - */ - if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address)) { - address -= bus->orig_ramsize; - address += SOCDEVRAM_BP_ADDR; - } - - /* Determine initial transfer parameters */ - sdaddr = address & SBSDIO_SB_OFT_ADDR_MASK; - if ((sdaddr + size) & SBSDIO_SBWINDOW_MASK) - dsize = (SBSDIO_SB_OFT_ADDR_LIMIT - sdaddr); - else - dsize = size; - - /* Set the backplane window to include the start address */ - if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { - DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); - goto xfer_done; - } - - /* Do the transfer(s) */ - while (size) { - DHD_INFO(("%s: %s %d bytes at offset 0x%08x in window 0x%08x\n", - __FUNCTION__, (write ? "write" : "read"), dsize, sdaddr, - (address & SBSDIO_SBWINDOW_MASK))); - if ((bcmerror = bcmsdh_rwdata(bus->sdh, write, sdaddr, data, dsize))) { - DHD_ERROR(("%s: membytes transfer failed\n", __FUNCTION__)); - break; - } - - /* Adjust for next transfer (if any) */ - if ((size -= dsize)) { - data += dsize; - address += dsize; - if ((bcmerror = dhdsdio_set_siaddr_window(bus, address))) { - DHD_ERROR(("%s: window change failed\n", __FUNCTION__)); - break; - } - sdaddr = 0; - dsize = MIN(SBSDIO_SB_OFT_ADDR_LIMIT, size); - } - - } - -xfer_done: - /* Return the window to backplane enumeration space for core access */ - if (dhdsdio_set_siaddr_window(bus, bcmsdh_cur_sbwad(bus->sdh))) { - DHD_ERROR(("%s: FAILED to set window back to 0x%x\n", __FUNCTION__, - bcmsdh_cur_sbwad(bus->sdh))); - } - - return bcmerror; -} - -#ifdef DHD_DEBUG -static int -dhdsdio_readshared(dhd_bus_t *bus, sdpcm_shared_t *sh) -{ - uint32 addr; - int rv, i; - uint32 shaddr = 0; - - shaddr = bus->ramsize - 4; - - i = 0; - do { - /* Read last word in memory to determine address of sdpcm_shared structure */ - if ((rv = dhdsdio_membytes(bus, FALSE, shaddr, (uint8 *)&addr, 4)) < 0) - return rv; - - addr = ltoh32(addr); - - DHD_INFO(("sdpcm_shared address 0x%08X\n", addr)); - - /* - * Check if addr is valid. - * NVRAM length at the end of memory should have been overwritten. - */ - if (addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)) { - if ((bus->srmemsize > 0) && (i++ == 0)) { - shaddr -= bus->srmemsize; - } else { - DHD_ERROR(("%s: address (0x%08x) of sdpcm_shared invalid\n", - __FUNCTION__, addr)); - return BCME_ERROR; - } - } else - break; - } while (i < 2); - - /* Read hndrte_shared structure */ - if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)sh, sizeof(sdpcm_shared_t))) < 0) - return rv; - - /* Endianness */ - sh->flags = ltoh32(sh->flags); - sh->trap_addr = ltoh32(sh->trap_addr); - sh->assert_exp_addr = ltoh32(sh->assert_exp_addr); - sh->assert_file_addr = ltoh32(sh->assert_file_addr); - sh->assert_line = ltoh32(sh->assert_line); - sh->console_addr = ltoh32(sh->console_addr); - sh->msgtrace_addr = ltoh32(sh->msgtrace_addr); - - if ((sh->flags & SDPCM_SHARED_VERSION_MASK) == 3 && SDPCM_SHARED_VERSION == 1) - return BCME_OK; - - if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { - DHD_ERROR(("%s: sdpcm_shared version %d in dhd " - "is different than sdpcm_shared version %d in dongle\n", - __FUNCTION__, SDPCM_SHARED_VERSION, - sh->flags & SDPCM_SHARED_VERSION_MASK)); - return BCME_ERROR; - } - - return BCME_OK; -} - -#define CONSOLE_LINE_MAX 192 - -static int -dhdsdio_readconsole(dhd_bus_t *bus) -{ - dhd_console_t *c = &bus->console; - uint8 line[CONSOLE_LINE_MAX], ch; - uint32 n, idx, addr; - int rv; - - /* Don't do anything until FWREADY updates console address */ - if (bus->console_addr == 0) - return 0; - - if (!KSO_ENAB(bus)) - return 0; - - /* Read console log struct */ - addr = bus->console_addr + OFFSETOF(hndrte_cons_t, log); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, (uint8 *)&c->log, sizeof(c->log))) < 0) - return rv; - - /* Allocate console buffer (one time only) */ - if (c->buf == NULL) { - c->bufsize = ltoh32(c->log.buf_size); - if ((c->buf = MALLOC(bus->dhd->osh, c->bufsize)) == NULL) - return BCME_NOMEM; - } - - idx = ltoh32(c->log.idx); - - /* Protect against corrupt value */ - if (idx > c->bufsize) - return BCME_ERROR; - - /* Skip reading the console buffer if the index pointer has not moved */ - if (idx == c->last) - return BCME_OK; - - /* Read the console buffer */ - addr = ltoh32(c->log.buf); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, c->buf, c->bufsize)) < 0) - return rv; - - while (c->last != idx) { - for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { - if (c->last == idx) { - /* This would output a partial line. Instead, back up - * the buffer pointer and output this line next time around. - */ - if (c->last >= n) - c->last -= n; - else - c->last = c->bufsize - n; - goto break2; - } - ch = c->buf[c->last]; - c->last = (c->last + 1) % c->bufsize; - if (ch == '\n') - break; - line[n] = ch; - } - - if (n > 0) { - if (line[n - 1] == '\r') - n--; - line[n] = 0; - printf("CONSOLE: %s\n", line); - } - } -break2: - - return BCME_OK; -} - -static int -dhdsdio_checkdied(dhd_bus_t *bus, char *data, uint size) -{ - int bcmerror = 0; - uint msize = 512; - char *mbuffer = NULL; - char *console_buffer = NULL; - uint maxstrlen = 256; - char *str = NULL; - trap_t tr; - sdpcm_shared_t sdpcm_shared; - struct bcmstrbuf strbuf; - uint32 console_ptr, console_size, console_index; - uint8 line[CONSOLE_LINE_MAX], ch; - uint32 n, i, addr; - int rv; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (data == NULL) { - /* - * Called after a rx ctrl timeout. "data" is NULL. - * allocate memory to trace the trap or assert. - */ - size = msize; - mbuffer = data = MALLOC(bus->dhd->osh, msize); - if (mbuffer == NULL) { - DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, msize)); - bcmerror = BCME_NOMEM; - goto done; - } - } - - if ((str = MALLOC(bus->dhd->osh, maxstrlen)) == NULL) { - DHD_ERROR(("%s: MALLOC(%d) failed \n", __FUNCTION__, maxstrlen)); - bcmerror = BCME_NOMEM; - goto done; - } - - if ((bcmerror = dhdsdio_readshared(bus, &sdpcm_shared)) < 0) - goto done; - - bcm_binit(&strbuf, data, size); - - bcm_bprintf(&strbuf, "msgtrace address : 0x%08X\nconsole address : 0x%08X\n", - sdpcm_shared.msgtrace_addr, sdpcm_shared.console_addr); - - if ((sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) { - /* NOTE: Misspelled assert is intentional - DO NOT FIX. - * (Avoids conflict with real asserts for programmatic parsing of output.) - */ - bcm_bprintf(&strbuf, "Assrt not built in dongle\n"); - } - - if ((sdpcm_shared.flags & (SDPCM_SHARED_ASSERT|SDPCM_SHARED_TRAP)) == 0) { - /* NOTE: Misspelled assert is intentional - DO NOT FIX. - * (Avoids conflict with real asserts for programmatic parsing of output.) - */ - bcm_bprintf(&strbuf, "No trap%s in dongle", - (sdpcm_shared.flags & SDPCM_SHARED_ASSERT_BUILT) - ?"/assrt" :""); - } else { - if (sdpcm_shared.flags & SDPCM_SHARED_ASSERT) { - /* Download assert */ - bcm_bprintf(&strbuf, "Dongle assert"); - if (sdpcm_shared.assert_exp_addr != 0) { - str[0] = '\0'; - if ((bcmerror = dhdsdio_membytes(bus, FALSE, - sdpcm_shared.assert_exp_addr, - (uint8 *)str, maxstrlen)) < 0) - goto done; - - str[maxstrlen - 1] = '\0'; - bcm_bprintf(&strbuf, " expr \"%s\"", str); - } - - if (sdpcm_shared.assert_file_addr != 0) { - str[0] = '\0'; - if ((bcmerror = dhdsdio_membytes(bus, FALSE, - sdpcm_shared.assert_file_addr, - (uint8 *)str, maxstrlen)) < 0) - goto done; - - str[maxstrlen - 1] = '\0'; - bcm_bprintf(&strbuf, " file \"%s\"", str); - } - - bcm_bprintf(&strbuf, " line %d ", sdpcm_shared.assert_line); - } - - if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) { - bus->dhd->dongle_trap_occured = TRUE; - if ((bcmerror = dhdsdio_membytes(bus, FALSE, - sdpcm_shared.trap_addr, - (uint8*)&tr, sizeof(trap_t))) < 0) - goto done; - - bcm_bprintf(&strbuf, - "Dongle trap type 0x%x @ epc 0x%x, cpsr 0x%x, spsr 0x%x, sp 0x%x," - "lp 0x%x, rpc 0x%x Trap offset 0x%x, " - "r0 0x%x, r1 0x%x, r2 0x%x, r3 0x%x, " - "r4 0x%x, r5 0x%x, r6 0x%x, r7 0x%x\n\n", - ltoh32(tr.type), ltoh32(tr.epc), ltoh32(tr.cpsr), ltoh32(tr.spsr), - ltoh32(tr.r13), ltoh32(tr.r14), ltoh32(tr.pc), - ltoh32(sdpcm_shared.trap_addr), - ltoh32(tr.r0), ltoh32(tr.r1), ltoh32(tr.r2), ltoh32(tr.r3), - ltoh32(tr.r4), ltoh32(tr.r5), ltoh32(tr.r6), ltoh32(tr.r7)); - - addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, - (uint8 *)&console_ptr, sizeof(console_ptr))) < 0) - goto printbuf; - - addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.buf_size); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, - (uint8 *)&console_size, sizeof(console_size))) < 0) - goto printbuf; - - addr = sdpcm_shared.console_addr + OFFSETOF(hndrte_cons_t, log.idx); - if ((rv = dhdsdio_membytes(bus, FALSE, addr, - (uint8 *)&console_index, sizeof(console_index))) < 0) - goto printbuf; - - console_ptr = ltoh32(console_ptr); - console_size = ltoh32(console_size); - console_index = ltoh32(console_index); - - if (console_size > CONSOLE_BUFFER_MAX || - !(console_buffer = MALLOC(bus->dhd->osh, console_size))) - goto printbuf; - - if ((rv = dhdsdio_membytes(bus, FALSE, console_ptr, - (uint8 *)console_buffer, console_size)) < 0) - goto printbuf; - - for (i = 0, n = 0; i < console_size; i += n + 1) { - for (n = 0; n < CONSOLE_LINE_MAX - 2; n++) { - ch = console_buffer[(console_index + i + n) % console_size]; - if (ch == '\n') - break; - line[n] = ch; - } - - - if (n > 0) { - if (line[n - 1] == '\r') - n--; - line[n] = 0; - /* Don't use DHD_ERROR macro since we print - * a lot of information quickly. The macro - * will truncate a lot of the printfs - */ - - if (dhd_msg_level & DHD_ERROR_VAL) - printf("CONSOLE: %s\n", line); - } - } - } - } - -printbuf: - if (sdpcm_shared.flags & (SDPCM_SHARED_ASSERT | SDPCM_SHARED_TRAP)) { - DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf)); - } - - -done: - if (mbuffer) - MFREE(bus->dhd->osh, mbuffer, msize); - if (str) - MFREE(bus->dhd->osh, str, maxstrlen); - if (console_buffer) - MFREE(bus->dhd->osh, console_buffer, console_size); - - return bcmerror; -} -#endif /* #ifdef DHD_DEBUG */ - - -int -dhdsdio_downloadvars(dhd_bus_t *bus, void *arg, int len) -{ - int bcmerror = BCME_OK; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Basic sanity checks */ - if (bus->dhd->up) { - bcmerror = BCME_NOTDOWN; - goto err; - } - if (!len) { - bcmerror = BCME_BUFTOOSHORT; - goto err; - } - - /* Free the old ones and replace with passed variables */ - if (bus->vars) - MFREE(bus->dhd->osh, bus->vars, bus->varsz); - - bus->vars = MALLOC(bus->dhd->osh, len); - bus->varsz = bus->vars ? len : 0; - if (bus->vars == NULL) { - bcmerror = BCME_NOMEM; - goto err; - } - - /* Copy the passed variables, which should include the terminating double-null */ - bcopy(arg, bus->vars, bus->varsz); -err: - return bcmerror; -} - -#ifdef DHD_DEBUG - -#define CC_PLL_CHIPCTRL_SERIAL_ENAB (1 << 24) -#define CC_CHIPCTRL_JTAG_SEL (1 << 3) -#define CC_CHIPCTRL_GPIO_SEL (0x3) -#define CC_PLL_CHIPCTRL_SERIAL_ENAB_4334 (1 << 28) - -static int -dhd_serialconsole(dhd_bus_t *bus, bool set, bool enable, int *bcmerror) -{ - int int_val; - uint32 addr, data, uart_enab = 0; - uint32 jtag_sel = CC_CHIPCTRL_JTAG_SEL; - uint32 gpio_sel = CC_CHIPCTRL_GPIO_SEL; - - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_addr); - data = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol_data); - *bcmerror = 0; - - bcmsdh_reg_write(bus->sdh, addr, 4, 1); - if (bcmsdh_regfail(bus->sdh)) { - *bcmerror = BCME_SDIO_ERROR; - return -1; - } - int_val = bcmsdh_reg_read(bus->sdh, data, 4); - if (bcmsdh_regfail(bus->sdh)) { - *bcmerror = BCME_SDIO_ERROR; - return -1; - } - if (bus->sih->chip == BCM4330_CHIP_ID) { - uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB; - } - else if (bus->sih->chip == BCM4334_CHIP_ID) { - if (enable) { - /* Moved to PMU chipcontrol 1 from 4330 */ - int_val &= ~gpio_sel; - int_val |= jtag_sel; - } else { - int_val |= gpio_sel; - int_val &= ~jtag_sel; - } - uart_enab = CC_PLL_CHIPCTRL_SERIAL_ENAB_4334; - } - - if (!set) - return (int_val & uart_enab); - if (enable) - int_val |= uart_enab; - else - int_val &= ~uart_enab; - bcmsdh_reg_write(bus->sdh, data, 4, int_val); - if (bcmsdh_regfail(bus->sdh)) { - *bcmerror = BCME_SDIO_ERROR; - return -1; - } - if (bus->sih->chip == BCM4330_CHIP_ID) { - uint32 chipcontrol; - addr = SI_ENUM_BASE + OFFSETOF(chipcregs_t, chipcontrol); - chipcontrol = bcmsdh_reg_read(bus->sdh, addr, 4); - chipcontrol &= ~jtag_sel; - if (enable) { - chipcontrol |= jtag_sel; - chipcontrol &= ~gpio_sel; - } - bcmsdh_reg_write(bus->sdh, addr, 4, chipcontrol); - } - - return (int_val & uart_enab); -} -#endif /* DHD_DEBUG */ - -static int -dhdsdio_doiovar(dhd_bus_t *bus, const bcm_iovar_t *vi, uint32 actionid, const char *name, - void *params, int plen, void *arg, int len, int val_size) -{ - int bcmerror = 0; - int32 int_val = 0; - bool bool_val = 0; - - DHD_TRACE(("%s: Enter, action %d name %s params %p plen %d arg %p len %d val_size %d\n", - __FUNCTION__, actionid, name, params, plen, arg, len, val_size)); - - if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, IOV_ISSET(actionid))) != 0) - goto exit; - - if (plen >= (int)sizeof(int_val)) - bcopy(params, &int_val, sizeof(int_val)); - - bool_val = (int_val != 0) ? TRUE : FALSE; - - - /* Some ioctls use the bus */ - dhd_os_sdlock(bus->dhd); - - /* Check if dongle is in reset. If so, only allow DEVRESET iovars */ - if (bus->dhd->dongle_reset && !(actionid == IOV_SVAL(IOV_DEVRESET) || - actionid == IOV_GVAL(IOV_DEVRESET))) { - bcmerror = BCME_NOTREADY; - goto exit; - } - - /* - * Special handling for keepSdioOn: New SDIO Wake-up Mechanism - */ - if ((vi->varid == IOV_KSO) && (IOV_ISSET(actionid))) { - dhdsdio_clk_kso_iovar(bus, bool_val); - goto exit; - } else if ((vi->varid == IOV_DEVSLEEP) && (IOV_ISSET(actionid))) { - { - dhdsdio_clk_devsleep_iovar(bus, bool_val); - if (!SLPAUTO_ENAB(bus) && (bool_val == FALSE) && (bus->ipend)) { - DHD_ERROR(("INT pending in devsleep 1, dpc_sched: %d\n", - bus->dpc_sched)); - if (!bus->dpc_sched) { - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - } - } - } - goto exit; - } - - /* Handle sleep stuff before any clock mucking */ - if (vi->varid == IOV_SLEEP) { - if (IOV_ISSET(actionid)) { - bcmerror = dhdsdio_bussleep(bus, bool_val); - } else { - int_val = (int32)bus->sleeping; - bcopy(&int_val, arg, val_size); - } - goto exit; - } - - /* Request clock to allow SDIO accesses */ - if (!bus->dhd->dongle_reset) { - BUS_WAKE(bus); - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - } - - switch (actionid) { - case IOV_GVAL(IOV_INTR): - int_val = (int32)bus->intr; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_INTR): - bus->intr = bool_val; - bus->intdis = FALSE; - if (bus->dhd->up) { - if (bus->intr) { - DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); - bcmsdh_intr_enable(bus->sdh); - } else { - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - bcmsdh_intr_disable(bus->sdh); - } - } - break; - - case IOV_GVAL(IOV_POLLRATE): - int_val = (int32)bus->pollrate; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_POLLRATE): - bus->pollrate = (uint)int_val; - bus->poll = (bus->pollrate != 0); - break; - - case IOV_GVAL(IOV_IDLETIME): - int_val = bus->idletime; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_IDLETIME): - if ((int_val < 0) && (int_val != DHD_IDLE_IMMEDIATE)) { - bcmerror = BCME_BADARG; - } else { - bus->idletime = int_val; - } - break; - - case IOV_GVAL(IOV_IDLECLOCK): - int_val = (int32)bus->idleclock; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_IDLECLOCK): - bus->idleclock = int_val; - break; - - case IOV_GVAL(IOV_SD1IDLE): - int_val = (int32)sd1idle; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SD1IDLE): - sd1idle = bool_val; - break; - - - case IOV_SVAL(IOV_MEMBYTES): - case IOV_GVAL(IOV_MEMBYTES): - { - uint32 address; - uint size, dsize; - uint8 *data; - - bool set = (actionid == IOV_SVAL(IOV_MEMBYTES)); - - ASSERT(plen >= 2*sizeof(int)); - - address = (uint32)int_val; - bcopy((char *)params + sizeof(int_val), &int_val, sizeof(int_val)); - size = (uint)int_val; - - /* Do some validation */ - dsize = set ? plen - (2 * sizeof(int)) : len; - if (dsize < size) { - DHD_ERROR(("%s: error on %s membytes, addr 0x%08x size %d dsize %d\n", - __FUNCTION__, (set ? "set" : "get"), address, size, dsize)); - bcmerror = BCME_BADARG; - break; - } - - DHD_INFO(("%s: Request to %s %d bytes at address 0x%08x\n", __FUNCTION__, - (set ? "write" : "read"), size, address)); - - /* If we know about SOCRAM, check for a fit */ - if ((bus->orig_ramsize) && - ((address > bus->orig_ramsize) || (address + size > bus->orig_ramsize))) - { - uint8 enable, protect, remap; - si_socdevram(bus->sih, FALSE, &enable, &protect, &remap); - if (!enable || protect) { - DHD_ERROR(("%s: ramsize 0x%08x doesn't have %d bytes at 0x%08x\n", - __FUNCTION__, bus->orig_ramsize, size, address)); - DHD_ERROR(("%s: socram enable %d, protect %d\n", - __FUNCTION__, enable, protect)); - bcmerror = BCME_BADARG; - break; - } - - if (!REMAP_ENAB(bus) && (address >= SOCDEVRAM_ARM_ADDR)) { - uint32 devramsize = si_socdevram_size(bus->sih); - if ((address < SOCDEVRAM_ARM_ADDR) || - (address + size > (SOCDEVRAM_ARM_ADDR + devramsize))) { - DHD_ERROR(("%s: bad address 0x%08x, size 0x%08x\n", - __FUNCTION__, address, size)); - DHD_ERROR(("%s: socram range 0x%08x,size 0x%08x\n", - __FUNCTION__, SOCDEVRAM_ARM_ADDR, devramsize)); - bcmerror = BCME_BADARG; - break; - } - /* move it such that address is real now */ - address -= SOCDEVRAM_ARM_ADDR; - address += SOCDEVRAM_BP_ADDR; - DHD_INFO(("%s: Request to %s %d bytes @ Mapped address 0x%08x\n", - __FUNCTION__, (set ? "write" : "read"), size, address)); - } else if (REMAP_ENAB(bus) && REMAP_ISADDR(bus, address) && remap) { - /* Can not access remap region while devram remap bit is set - * ROM content would be returned in this case - */ - DHD_ERROR(("%s: Need to disable remap for address 0x%08x\n", - __FUNCTION__, address)); - bcmerror = BCME_ERROR; - break; - } - } - - /* Generate the actual data pointer */ - data = set ? (uint8*)params + 2 * sizeof(int): (uint8*)arg; - - /* Call to do the transfer */ - bcmerror = dhdsdio_membytes(bus, set, address, data, size); - - break; - } - - case IOV_GVAL(IOV_MEMSIZE): - int_val = (int32)bus->ramsize; - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_SDIOD_DRIVE): - int_val = (int32)dhd_sdiod_drive_strength; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDIOD_DRIVE): - dhd_sdiod_drive_strength = int_val; - si_sdiod_drive_strength_init(bus->sih, bus->dhd->osh, dhd_sdiod_drive_strength); - break; - - case IOV_SVAL(IOV_SET_DOWNLOAD_STATE): - bcmerror = dhdsdio_download_state(bus, bool_val); - break; - - case IOV_SVAL(IOV_SOCRAM_STATE): - bcmerror = dhdsdio_download_state(bus, bool_val); - break; - - case IOV_SVAL(IOV_VARS): - bcmerror = dhdsdio_downloadvars(bus, arg, len); - break; - - case IOV_GVAL(IOV_READAHEAD): - int_val = (int32)dhd_readahead; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_READAHEAD): - if (bool_val && !dhd_readahead) - bus->nextlen = 0; - dhd_readahead = bool_val; - break; - - case IOV_GVAL(IOV_SDRXCHAIN): - int_val = (int32)bus->use_rxchain; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SDRXCHAIN): - if (bool_val && !bus->sd_rxchain) - bcmerror = BCME_UNSUPPORTED; - else - bus->use_rxchain = bool_val; - break; - case IOV_GVAL(IOV_ALIGNCTL): - int_val = (int32)dhd_alignctl; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_ALIGNCTL): - dhd_alignctl = bool_val; - break; - - case IOV_GVAL(IOV_SDALIGN): - int_val = DHD_SDALIGN; - bcopy(&int_val, arg, val_size); - break; - -#ifdef DHD_DEBUG - case IOV_GVAL(IOV_VARS): - if (bus->varsz < (uint)len) - bcopy(bus->vars, arg, bus->varsz); - else - bcmerror = BCME_BUFTOOSHORT; - break; -#endif /* DHD_DEBUG */ - -#ifdef DHD_DEBUG - case IOV_GVAL(IOV_SDREG): - { - sdreg_t *sd_ptr; - uint32 addr, size; - - sd_ptr = (sdreg_t *)params; - - addr = (uintptr)bus->regs + sd_ptr->offset; - size = sd_ptr->func; - int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); - if (bcmsdh_regfail(bus->sdh)) - bcmerror = BCME_SDIO_ERROR; - bcopy(&int_val, arg, sizeof(int32)); - break; - } - - case IOV_SVAL(IOV_SDREG): - { - sdreg_t *sd_ptr; - uint32 addr, size; - - sd_ptr = (sdreg_t *)params; - - addr = (uintptr)bus->regs + sd_ptr->offset; - size = sd_ptr->func; - bcmsdh_reg_write(bus->sdh, addr, size, sd_ptr->value); - if (bcmsdh_regfail(bus->sdh)) - bcmerror = BCME_SDIO_ERROR; - break; - } - - /* Same as above, but offset is not backplane (not SDIO core) */ - case IOV_GVAL(IOV_SBREG): - { - sdreg_t sdreg; - uint32 addr, size; - - bcopy(params, &sdreg, sizeof(sdreg)); - - addr = SI_ENUM_BASE + sdreg.offset; - size = sdreg.func; - int_val = (int32)bcmsdh_reg_read(bus->sdh, addr, size); - if (bcmsdh_regfail(bus->sdh)) - bcmerror = BCME_SDIO_ERROR; - bcopy(&int_val, arg, sizeof(int32)); - break; - } - - case IOV_SVAL(IOV_SBREG): - { - sdreg_t sdreg; - uint32 addr, size; - - bcopy(params, &sdreg, sizeof(sdreg)); - - addr = SI_ENUM_BASE + sdreg.offset; - size = sdreg.func; - bcmsdh_reg_write(bus->sdh, addr, size, sdreg.value); - if (bcmsdh_regfail(bus->sdh)) - bcmerror = BCME_SDIO_ERROR; - break; - } - - case IOV_GVAL(IOV_SDCIS): - { - *(char *)arg = 0; - - bcmstrcat(arg, "\nFunc 0\n"); - bcmsdh_cis_read(bus->sdh, 0x10, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); - bcmstrcat(arg, "\nFunc 1\n"); - bcmsdh_cis_read(bus->sdh, 0x11, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); - bcmstrcat(arg, "\nFunc 2\n"); - bcmsdh_cis_read(bus->sdh, 0x12, (uint8 *)arg + strlen(arg), SBSDIO_CIS_SIZE_LIMIT); - break; - } - - case IOV_GVAL(IOV_FORCEEVEN): - int_val = (int32)forcealign; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_FORCEEVEN): - forcealign = bool_val; - break; - - case IOV_GVAL(IOV_TXBOUND): - int_val = (int32)dhd_txbound; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_TXBOUND): - dhd_txbound = (uint)int_val; - break; - - case IOV_GVAL(IOV_RXBOUND): - int_val = (int32)dhd_rxbound; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_RXBOUND): - dhd_rxbound = (uint)int_val; - break; - - case IOV_GVAL(IOV_TXMINMAX): - int_val = (int32)dhd_txminmax; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_TXMINMAX): - dhd_txminmax = (uint)int_val; - break; - - case IOV_GVAL(IOV_SERIALCONS): - int_val = dhd_serialconsole(bus, FALSE, 0, &bcmerror); - if (bcmerror != 0) - break; - - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_SERIALCONS): - dhd_serialconsole(bus, TRUE, bool_val, &bcmerror); - break; -#endif /* DHD_DEBUG */ - - -#ifdef SDTEST - case IOV_GVAL(IOV_EXTLOOP): - int_val = (int32)bus->ext_loop; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_EXTLOOP): - bus->ext_loop = bool_val; - break; - - case IOV_GVAL(IOV_PKTGEN): - bcmerror = dhdsdio_pktgen_get(bus, arg); - break; - - case IOV_SVAL(IOV_PKTGEN): - bcmerror = dhdsdio_pktgen_set(bus, arg); - break; -#endif /* SDTEST */ - - - case IOV_GVAL(IOV_DONGLEISOLATION): - int_val = bus->dhd->dongle_isolation; - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DONGLEISOLATION): - bus->dhd->dongle_isolation = bool_val; - break; - - case IOV_SVAL(IOV_DEVRESET): - DHD_TRACE(("%s: Called set IOV_DEVRESET=%d dongle_reset=%d busstate=%d\n", - __FUNCTION__, bool_val, bus->dhd->dongle_reset, - bus->dhd->busstate)); - - ASSERT(bus->dhd->osh); - /* ASSERT(bus->cl_devid); */ - - dhd_bus_devreset(bus->dhd, (uint8)bool_val); - - break; -#ifdef SOFTAP - case IOV_GVAL(IOV_FWPATH): - { - uint32 fw_path_len; - - fw_path_len = strlen(bus->fw_path); - DHD_INFO(("[softap] get fwpath, l=%d\n", len)); - - if (fw_path_len > len-1) { - bcmerror = BCME_BUFTOOSHORT; - break; - } - - if (fw_path_len) { - bcopy(bus->fw_path, arg, fw_path_len); - ((uchar*)arg)[fw_path_len] = 0; - } - break; - } - - case IOV_SVAL(IOV_FWPATH): - DHD_INFO(("[softap] set fwpath, idx=%d\n", int_val)); - - switch (int_val) { - case 1: - bus->fw_path = fw_path; /* ordinary one */ - break; - case 2: - bus->fw_path = fw_path2; - break; - default: - bcmerror = BCME_BADARG; - break; - } - - DHD_INFO(("[softap] new fw path: %s\n", (bus->fw_path[0] ? bus->fw_path : "NULL"))); - break; - -#endif /* SOFTAP */ - case IOV_GVAL(IOV_DEVRESET): - DHD_TRACE(("%s: Called get IOV_DEVRESET\n", __FUNCTION__)); - - /* Get its status */ - int_val = (bool) bus->dhd->dongle_reset; - bcopy(&int_val, arg, val_size); - - break; - - case IOV_GVAL(IOV_KSO): - int_val = dhdsdio_sleepcsr_get(bus); - bcopy(&int_val, arg, val_size); - break; - - case IOV_GVAL(IOV_DEVCAP): - int_val = dhdsdio_devcap_get(bus); - bcopy(&int_val, arg, val_size); - break; - - case IOV_SVAL(IOV_DEVCAP): - dhdsdio_devcap_set(bus, (uint8) int_val); - break; - - default: - bcmerror = BCME_UNSUPPORTED; - break; - } - -exit: - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - - return bcmerror; -} - -static int -dhdsdio_write_vars(dhd_bus_t *bus) -{ - int bcmerror = 0; - uint32 varsize, phys_size; - uint32 varaddr; - uint8 *vbuffer; - uint32 varsizew; -#ifdef DHD_DEBUG - uint8 *nvram_ularray; -#endif /* DHD_DEBUG */ - - /* Even if there are no vars are to be written, we still need to set the ramsize. */ - varsize = bus->varsz ? ROUNDUP(bus->varsz, 4) : 0; - varaddr = (bus->ramsize - 4) - varsize; - - if (bus->vars) { - if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 7)) { - if (((varaddr & 0x3C) == 0x3C) && (varsize > 4)) { - DHD_ERROR(("PR85623WAR in place\n")); - varsize += 4; - varaddr -= 4; - } - } - - vbuffer = (uint8 *)MALLOC(bus->dhd->osh, varsize); - if (!vbuffer) - return BCME_NOMEM; - - bzero(vbuffer, varsize); - bcopy(bus->vars, vbuffer, bus->varsz); - - /* Write the vars list */ - bcmerror = dhdsdio_membytes(bus, TRUE, varaddr, vbuffer, varsize); -#ifdef DHD_DEBUG - /* Verify NVRAM bytes */ - DHD_INFO(("Compare NVRAM dl & ul; varsize=%d\n", varsize)); - nvram_ularray = (uint8*)MALLOC(bus->dhd->osh, varsize); - if (!nvram_ularray) - return BCME_NOMEM; - - /* Upload image to verify downloaded contents. */ - memset(nvram_ularray, 0xaa, varsize); - - /* Read the vars list to temp buffer for comparison */ - bcmerror = dhdsdio_membytes(bus, FALSE, varaddr, nvram_ularray, varsize); - if (bcmerror) { - DHD_ERROR(("%s: error %d on reading %d nvram bytes at 0x%08x\n", - __FUNCTION__, bcmerror, varsize, varaddr)); - } - /* Compare the org NVRAM with the one read from RAM */ - if (memcmp(vbuffer, nvram_ularray, varsize)) { - DHD_ERROR(("%s: Downloaded NVRAM image is corrupted.\n", __FUNCTION__)); - } else - DHD_ERROR(("%s: Download, Upload and compare of NVRAM succeeded.\n", - __FUNCTION__)); - - MFREE(bus->dhd->osh, nvram_ularray, varsize); -#endif /* DHD_DEBUG */ - - MFREE(bus->dhd->osh, vbuffer, varsize); - } - - phys_size = REMAP_ENAB(bus) ? bus->ramsize : bus->orig_ramsize; - - /* adjust to the user specified RAM */ - DHD_INFO(("Physical memory size: %d, usable memory size: %d\n", - phys_size, bus->ramsize)); - DHD_INFO(("Vars are at %d, orig varsize is %d\n", - varaddr, varsize)); - varsize = ((phys_size - 4) - varaddr); - - /* - * Determine the length token: - * Varsize, converted to words, in lower 16-bits, checksum in upper 16-bits. - */ - if (bcmerror) { - varsizew = 0; - } else { - varsizew = varsize / 4; - varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); - varsizew = htol32(varsizew); - } - - DHD_INFO(("New varsize is %d, length token=0x%08x\n", varsize, varsizew)); - - /* Write the length token to the last word */ - bcmerror = dhdsdio_membytes(bus, TRUE, (phys_size - 4), - (uint8*)&varsizew, 4); - - return bcmerror; -} - -static int -dhdsdio_download_state(dhd_bus_t *bus, bool enter) -{ - uint retries; - int bcmerror = 0; - - /* To enter download state, disable ARM and reset SOCRAM. - * To exit download state, simply reset ARM (default is RAM boot). - */ - if (enter) { - bus->alp_only = TRUE; - - if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && - !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - si_core_disable(bus->sih, 0); - if (bcmsdh_regfail(bus->sdh)) { - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - - if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - si_core_reset(bus->sih, 0, 0); - if (bcmsdh_regfail(bus->sdh)) { - DHD_ERROR(("%s: Failure trying reset SOCRAM core?\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - - /* Disable remap for download */ - if (REMAP_ENAB(bus) && si_socdevram_remap_isenb(bus->sih)) - dhdsdio_devram_remap(bus, FALSE); - - /* Clear the top bit of memory */ - if (bus->ramsize) { - uint32 zeros = 0; - if (dhdsdio_membytes(bus, TRUE, bus->ramsize - 4, (uint8*)&zeros, 4) < 0) { - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - } - } else { - if (!(si_setcore(bus->sih, SOCRAM_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find SOCRAM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - if (!si_iscoreup(bus->sih)) { - DHD_ERROR(("%s: SOCRAM core is down after reset?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - if ((bcmerror = dhdsdio_write_vars(bus))) { - DHD_ERROR(("%s: could not write vars to RAM\n", __FUNCTION__)); - goto fail; - } - - /* Enable remap before ARM reset but after vars. - * No backplane access in remap mode - */ - if (REMAP_ENAB(bus) && !si_socdevram_remap_isenb(bus->sih)) - dhdsdio_devram_remap(bus, TRUE); - - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0) && - !si_setcore(bus->sih, SDIOD_CORE_ID, 0)) { - DHD_ERROR(("%s: Can't change back to SDIO core?\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - W_SDREG(0xFFFFFFFF, &bus->regs->intstatus, retries); - - - if (!(si_setcore(bus->sih, ARM7S_CORE_ID, 0)) && - !(si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { - DHD_ERROR(("%s: Failed to find ARM core!\n", __FUNCTION__)); - bcmerror = BCME_ERROR; - goto fail; - } - - si_core_reset(bus->sih, 0, 0); - if (bcmsdh_regfail(bus->sdh)) { - DHD_ERROR(("%s: Failure trying to reset ARM core?\n", __FUNCTION__)); - bcmerror = BCME_SDIO_ERROR; - goto fail; - } - - /* Allow HT Clock now that the ARM is running. */ - bus->alp_only = FALSE; - - bus->dhd->busstate = DHD_BUS_LOAD; - } - -fail: - /* Always return to SDIOD core */ - if (!si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) - si_setcore(bus->sih, SDIOD_CORE_ID, 0); - - return bcmerror; -} - -int -dhd_bus_iovar_op(dhd_pub_t *dhdp, const char *name, - void *params, int plen, void *arg, int len, bool set) -{ - dhd_bus_t *bus = dhdp->bus; - const bcm_iovar_t *vi = NULL; - int bcmerror = 0; - int val_size; - uint32 actionid; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(name); - ASSERT(len >= 0); - - /* Get MUST have return space */ - ASSERT(set || (arg && len)); - - /* Set does NOT take qualifiers */ - ASSERT(!set || (!params && !plen)); - - /* Look up var locally; if not found pass to host driver */ - if ((vi = bcm_iovar_lookup(dhdsdio_iovars, name)) == NULL) { - dhd_os_sdlock(bus->dhd); - - BUS_WAKE(bus); - - /* Turn on clock in case SD command needs backplane */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - bcmerror = bcmsdh_iovar_op(bus->sdh, name, params, plen, arg, len, set); - - /* Check for bus configuration changes of interest */ - - /* If it was divisor change, read the new one */ - if (set && strcmp(name, "sd_divisor") == 0) { - if (bcmsdh_iovar_op(bus->sdh, "sd_divisor", NULL, 0, - &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { - bus->sd_divisor = -1; - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); - } else { - DHD_INFO(("%s: noted %s update, value now %d\n", - __FUNCTION__, name, bus->sd_divisor)); - } - } - /* If it was a mode change, read the new one */ - if (set && strcmp(name, "sd_mode") == 0) { - if (bcmsdh_iovar_op(bus->sdh, "sd_mode", NULL, 0, - &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { - bus->sd_mode = -1; - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, name)); - } else { - DHD_INFO(("%s: noted %s update, value now %d\n", - __FUNCTION__, name, bus->sd_mode)); - } - } - /* Similar check for blocksize change */ - if (set && strcmp(name, "sd_blocksize") == 0) { - int32 fnum = 2; - if (bcmsdh_iovar_op(bus->sdh, "sd_blocksize", &fnum, sizeof(int32), - &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { - bus->blocksize = 0; - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); - } else { - DHD_INFO(("%s: noted %s update, value now %d\n", - __FUNCTION__, "sd_blocksize", bus->blocksize)); - } - } - bus->roundup = MIN(max_roundup, bus->blocksize); - - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - goto exit; - } - - DHD_CTL(("%s: %s %s, len %d plen %d\n", __FUNCTION__, - name, (set ? "set" : "get"), len, plen)); - - /* set up 'params' pointer in case this is a set command so that - * the convenience int and bool code can be common to set and get - */ - if (params == NULL) { - params = arg; - plen = len; - } - - if (vi->type == IOVT_VOID) - val_size = 0; - else if (vi->type == IOVT_BUFFER) - val_size = len; - else - /* all other types are integer sized */ - val_size = sizeof(int); - - actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid); - bcmerror = dhdsdio_doiovar(bus, vi, actionid, name, params, plen, arg, len, val_size); - -exit: - return bcmerror; -} - -void -dhd_bus_stop(struct dhd_bus *bus, bool enforce_mutex) -{ - osl_t *osh; - uint32 local_hostintmask; - uint8 saveclk; - uint retries; - int err; - if (!bus->dhd) - return; - - osh = bus->dhd->osh; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - bcmsdh_waitlockfree(NULL); - - if (enforce_mutex) - dhd_os_sdlock(bus->dhd); - - BUS_WAKE(bus); - - /* Change our idea of bus state */ - bus->dhd->busstate = DHD_BUS_DOWN; - - if (KSO_ENAB(bus)) { - - /* Enable clock for device interrupts */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Disable and clear interrupts at the chip level also */ - W_SDREG(0, &bus->regs->hostintmask, retries); - local_hostintmask = bus->hostintmask; - bus->hostintmask = 0; - - /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (!err) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - (saveclk | SBSDIO_FORCE_HT), &err); - } - if (err) { - DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err)); - } - - /* Turn off the bus (F2), free any pending packets */ - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - bcmsdh_intr_disable(bus->sdh); - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); - - /* Clear any pending interrupts now that F2 is disabled */ - W_SDREG(local_hostintmask, &bus->regs->intstatus, retries); - } - - /* Turn off the backplane clock (only) */ - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - - /* Clear the data packet queues */ - pktq_flush(osh, &bus->txq, TRUE, NULL, 0); - - /* Clear any held glomming stuff */ - if (bus->glomd) - PKTFREE(osh, bus->glomd, FALSE); - - if (bus->glom) - PKTFREE(osh, bus->glom, FALSE); - - bus->glom = bus->glomd = NULL; - - /* Clear rx control and wake any waiters */ - bus->rxlen = 0; - dhd_os_ioctl_resp_wake(bus->dhd); - - /* Reset some F2 state stuff */ - bus->rxskip = FALSE; - bus->tx_seq = bus->rx_seq = 0; - - if (enforce_mutex) - dhd_os_sdunlock(bus->dhd); -} - - -int -dhd_bus_init(dhd_pub_t *dhdp, bool enforce_mutex) -{ - dhd_bus_t *bus = dhdp->bus; - dhd_timeout_t tmo; - uint retries = 0; - uint8 ready, enable; - int err, ret = 0; - uint8 saveclk; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - ASSERT(bus->dhd); - if (!bus->dhd) - return 0; - - if (enforce_mutex) - dhd_os_sdlock(bus->dhd); - - /* Make sure backplane clock is on, needed to generate F2 interrupt */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - if (bus->clkstate != CLK_AVAIL) { - DHD_ERROR(("%s: clock state is wrong. state = %d\n", __FUNCTION__, bus->clkstate)); - goto exit; - } - - - /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (!err) { - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - (saveclk | SBSDIO_FORCE_HT), &err); - } - if (err) { - DHD_ERROR(("%s: Failed to force clock for F2: err %d\n", __FUNCTION__, err)); - goto exit; - } - - /* Enable function 2 (frame transfers) */ - W_SDREG((SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT), - &bus->regs->tosbmailboxdata, retries); - enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); - - /* Give the dongle some time to do its thing and set IOR2 */ - dhd_timeout_start(&tmo, DHD_WAIT_F2RDY * 1000); - - ready = 0; - while (ready != enable && !dhd_timeout_expired(&tmo)) - ready = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IORDY, NULL); - - DHD_INFO(("%s: enable 0x%02x, ready 0x%02x (waited %uus)\n", - __FUNCTION__, enable, ready, tmo.elapsed)); - - - /* If F2 successfully enabled, set core and enable interrupts */ - if (ready == enable) { - /* Make sure we're talking to the core. */ - if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0))) - bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0); - ASSERT(bus->regs != NULL); - - /* Set up the interrupt mask and enable interrupts */ - bus->hostintmask = HOSTINTMASK; - /* corerev 4 could use the newer interrupt logic to detect the frames */ - if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev == 4) && - (bus->rxint_mode != SDIO_DEVICE_HMB_RXINT)) { - bus->hostintmask &= ~I_HMB_FRAME_IND; - bus->hostintmask |= I_XMTDATA_AVAIL; - } - W_SDREG(bus->hostintmask, &bus->regs->hostintmask, retries); - - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, SBSDIO_WATERMARK, (uint8)watermark, &err); - - /* Set bus state according to enable result */ - dhdp->busstate = DHD_BUS_DATA; - - /* bcmsdh_intr_unmask(bus->sdh); */ - - bus->intdis = FALSE; - if (bus->intr) { - DHD_INTR(("%s: enable SDIO device interrupts\n", __FUNCTION__)); - bcmsdh_intr_enable(bus->sdh); - } else { - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - bcmsdh_intr_disable(bus->sdh); - } - - } - - - else { - /* Disable F2 again */ - enable = SDIO_FUNC_ENABLE_1; - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, enable, NULL); - } - -#ifdef BCM4334_CHIP - if (dhdsdio_sr_cap(bus)) - dhdsdio_sr_init(bus); - else -#endif /* BCM4334_CHIP */ - bcmsdh_cfg_write(bus->sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); - - /* If we didn't come up, turn off backplane clock */ - if (dhdp->busstate != DHD_BUS_DATA) - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - -exit: - if (enforce_mutex) - dhd_os_sdunlock(bus->dhd); - - return ret; -} - -static void -dhdsdio_rxfail(dhd_bus_t *bus, bool abort, bool rtx) -{ - bcmsdh_info_t *sdh = bus->sdh; - sdpcmd_regs_t *regs = bus->regs; - uint retries = 0; - uint16 lastrbc; - uint8 hi, lo; - int err; - - DHD_ERROR(("%s: %sterminate frame%s\n", __FUNCTION__, - (abort ? "abort command, " : ""), (rtx ? ", send NAK" : ""))); - - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - return; - } - - if (abort) { - bcmsdh_abort(sdh, SDIO_FUNC_2); - } - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err); - bus->f1regdata++; - - /* Wait until the packet has been flushed (device/FIFO stable) */ - for (lastrbc = retries = 0xffff; retries > 0; retries--) { - hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCHI, NULL); - lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_RFRAMEBCLO, NULL); - bus->f1regdata += 2; - - if ((hi == 0) && (lo == 0)) - break; - - if ((hi > (lastrbc >> 8)) && (lo > (lastrbc & 0x00ff))) { - DHD_ERROR(("%s: count growing: last 0x%04x now 0x%04x\n", - __FUNCTION__, lastrbc, ((hi << 8) + lo))); - } - lastrbc = (hi << 8) + lo; - } - - if (!retries) { - DHD_ERROR(("%s: count never zeroed: last 0x%04x\n", __FUNCTION__, lastrbc)); - } else { - DHD_INFO(("%s: flush took %d iterations\n", __FUNCTION__, (0xffff - retries))); - } - - if (rtx) { - bus->rxrtx++; - W_SDREG(SMB_NAK, ®s->tosbmailbox, retries); - bus->f1regdata++; - if (retries <= retry_limit) { - bus->rxskip = TRUE; - } - } - - /* Clear partial in any case */ - bus->nextlen = 0; - - /* If we can't reach the device, signal failure */ - if (err || bcmsdh_regfail(sdh)) - bus->dhd->busstate = DHD_BUS_DOWN; -} - -static void -dhdsdio_read_control(dhd_bus_t *bus, uint8 *hdr, uint len, uint doff) -{ - bcmsdh_info_t *sdh = bus->sdh; - uint rdlen, pad; - - int sdret; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Control data already received in aligned rxctl */ - if ((bus->bus == SPI_BUS) && (!bus->usebufpool)) - goto gotpkt; - - ASSERT(bus->rxbuf); - /* Set rxctl for frame (w/optional alignment) */ - bus->rxctl = bus->rxbuf; - if (dhd_alignctl) { - bus->rxctl += firstread; - if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) - bus->rxctl += (DHD_SDALIGN - pad); - bus->rxctl -= firstread; - } - ASSERT(bus->rxctl >= bus->rxbuf); - - /* Copy the already-read portion over */ - bcopy(hdr, bus->rxctl, firstread); - if (len <= firstread) - goto gotpkt; - - /* Copy the full data pkt in gSPI case and process ioctl. */ - if (bus->bus == SPI_BUS) { - bcopy(hdr, bus->rxctl, len); - goto gotpkt; - } - - /* Raise rdlen to next SDIO block to avoid tail command */ - rdlen = len - firstread; - if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { - pad = bus->blocksize - (rdlen % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize) && - ((len + pad) < bus->dhd->maxctl)) - rdlen += pad; - } else if (rdlen % DHD_SDALIGN) { - rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); - } - - /* Satisfy length-alignment requirements */ - if (forcealign && (rdlen & (ALIGNMENT - 1))) - rdlen = ROUNDUP(rdlen, ALIGNMENT); - - /* Drop if the read is too big or it exceeds our maximum */ - if ((rdlen + firstread) > bus->dhd->maxctl) { - DHD_ERROR(("%s: %d-byte control read exceeds %d-byte buffer\n", - __FUNCTION__, rdlen, bus->dhd->maxctl)); - bus->dhd->rx_errors++; - dhdsdio_rxfail(bus, FALSE, FALSE); - goto done; - } - - if ((len - doff) > bus->dhd->maxctl) { - DHD_ERROR(("%s: %d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", - __FUNCTION__, len, (len - doff), bus->dhd->maxctl)); - bus->dhd->rx_errors++; bus->rx_toolong++; - dhdsdio_rxfail(bus, FALSE, FALSE); - goto done; - } - - - /* Read remainder of frame body into the rxctl buffer */ - sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - (bus->rxctl + firstread), rdlen, NULL, NULL, NULL); - bus->f2rxdata++; - ASSERT(sdret != BCME_PENDING); - - /* Control frame failures need retransmission */ - if (sdret < 0) { - DHD_ERROR(("%s: read %d control bytes failed: %d\n", __FUNCTION__, rdlen, sdret)); - bus->rxc_errors++; /* dhd.rx_ctlerrs is higher level */ - dhdsdio_rxfail(bus, TRUE, TRUE); - goto done; - } - -gotpkt: - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_CTL_ON()) { - prhex("RxCtrl", bus->rxctl, len); - } -#endif - - /* Point to valid data and indicate its length */ - bus->rxctl += doff; - bus->rxlen = len - doff; - -done: - /* Awake any waiters */ - dhd_os_ioctl_resp_wake(bus->dhd); -} - -static uint8 -dhdsdio_rxglom(dhd_bus_t *bus, uint8 rxseq) -{ - uint16 dlen, totlen; - uint8 *dptr, num = 0; - - uint16 sublen, check; - void *pfirst, *plast, *pnext; - void * list_tail[DHD_MAX_IFS] = { NULL }; - void * list_head[DHD_MAX_IFS] = { NULL }; - uint8 idx; - osl_t *osh = bus->dhd->osh; - - int errcode; - uint8 chan, seq, doff, sfdoff; - uint8 txmax; - uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; - uint reorder_info_len; - - int ifidx = 0; - bool usechain = bus->use_rxchain; - - /* If packets, issue read(s) and send up packet chain */ - /* Return sequence numbers consumed? */ - - DHD_TRACE(("dhdsdio_rxglom: start: glomd %p glom %p\n", bus->glomd, bus->glom)); - - /* If there's a descriptor, generate the packet chain */ - if (bus->glomd) { - dhd_os_sdlock_rxq(bus->dhd); - - pfirst = plast = pnext = NULL; - dlen = (uint16)PKTLEN(osh, bus->glomd); - dptr = PKTDATA(osh, bus->glomd); - if (!dlen || (dlen & 1)) { - DHD_ERROR(("%s: bad glomd len (%d), ignore descriptor\n", - __FUNCTION__, dlen)); - dlen = 0; - } - - for (totlen = num = 0; dlen; num++) { - /* Get (and move past) next length */ - sublen = ltoh16_ua(dptr); - dlen -= sizeof(uint16); - dptr += sizeof(uint16); - if ((sublen < SDPCM_HDRLEN) || - ((num == 0) && (sublen < (2 * SDPCM_HDRLEN)))) { - DHD_ERROR(("%s: descriptor len %d bad: %d\n", - __FUNCTION__, num, sublen)); - pnext = NULL; - break; - } - if (sublen % DHD_SDALIGN) { - DHD_ERROR(("%s: sublen %d not a multiple of %d\n", - __FUNCTION__, sublen, DHD_SDALIGN)); - usechain = FALSE; - } - totlen += sublen; - - /* For last frame, adjust read len so total is a block multiple */ - if (!dlen) { - sublen += (ROUNDUP(totlen, bus->blocksize) - totlen); - totlen = ROUNDUP(totlen, bus->blocksize); - } - - /* Allocate/chain packet for next subframe */ - if ((pnext = PKTGET(osh, sublen + DHD_SDALIGN, FALSE)) == NULL) { - DHD_ERROR(("%s: PKTGET failed, num %d len %d\n", - __FUNCTION__, num, sublen)); - break; - } - ASSERT(!PKTLINK(pnext)); - if (!pfirst) { - ASSERT(!plast); - pfirst = plast = pnext; - } else { - ASSERT(plast); - PKTSETNEXT(osh, plast, pnext); - plast = pnext; - } - - /* Adhere to start alignment requirements */ - PKTALIGN(osh, pnext, sublen, DHD_SDALIGN); - } - - /* If all allocations succeeded, save packet chain in bus structure */ - if (pnext) { - DHD_GLOM(("%s: allocated %d-byte packet chain for %d subframes\n", - __FUNCTION__, totlen, num)); - if (DHD_GLOM_ON() && bus->nextlen) { - if (totlen != bus->nextlen) { - DHD_GLOM(("%s: glomdesc mismatch: nextlen %d glomdesc %d " - "rxseq %d\n", __FUNCTION__, bus->nextlen, - totlen, rxseq)); - } - } - bus->glom = pfirst; - pfirst = pnext = NULL; - } else { - if (pfirst) - PKTFREE(osh, pfirst, FALSE); - bus->glom = NULL; - num = 0; - } - - /* Done with descriptor packet */ - PKTFREE(osh, bus->glomd, FALSE); - bus->glomd = NULL; - bus->nextlen = 0; - - dhd_os_sdunlock_rxq(bus->dhd); - } - - /* Ok -- either we just generated a packet chain, or had one from before */ - if (bus->glom) { - if (DHD_GLOM_ON()) { - DHD_GLOM(("%s: attempt superframe read, packet chain:\n", __FUNCTION__)); - for (pnext = bus->glom; pnext; pnext = PKTNEXT(osh, pnext)) { - DHD_GLOM((" %p: %p len 0x%04x (%d)\n", - pnext, (uint8*)PKTDATA(osh, pnext), - PKTLEN(osh, pnext), PKTLEN(osh, pnext))); - } - } - - pfirst = bus->glom; - dlen = (uint16)pkttotlen(osh, pfirst); - - /* Do an SDIO read for the superframe. Configurable iovar to - * read directly into the chained packet, or allocate a large - * packet and and copy into the chain. - */ - if (usechain) { - errcode = dhd_bcmsdh_recv_buf(bus, - bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, - F2SYNC, (uint8*)PKTDATA(osh, pfirst), - dlen, pfirst, NULL, NULL); - } else if (bus->dataptr) { - errcode = dhd_bcmsdh_recv_buf(bus, - bcmsdh_cur_sbwad(bus->sdh), SDIO_FUNC_2, - F2SYNC, bus->dataptr, - dlen, NULL, NULL, NULL); - sublen = (uint16)pktfrombuf(osh, pfirst, 0, dlen, bus->dataptr); - if (sublen != dlen) { - DHD_ERROR(("%s: FAILED TO COPY, dlen %d sublen %d\n", - __FUNCTION__, dlen, sublen)); - errcode = -1; - } - pnext = NULL; - } else { - DHD_ERROR(("COULDN'T ALLOC %d-BYTE GLOM, FORCE FAILURE\n", dlen)); - errcode = -1; - } - bus->f2rxdata++; - ASSERT(errcode != BCME_PENDING); - - /* On failure, kill the superframe, allow a couple retries */ - if (errcode < 0) { - DHD_ERROR(("%s: glom read of %d bytes failed: %d\n", - __FUNCTION__, dlen, errcode)); - bus->dhd->rx_errors++; - - if (bus->glomerr++ < 3) { - dhdsdio_rxfail(bus, TRUE, TRUE); - } else { - bus->glomerr = 0; - dhdsdio_rxfail(bus, TRUE, FALSE); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(osh, bus->glom, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - bus->rxglomfail++; - bus->glom = NULL; - } - return 0; - } - -#ifdef DHD_DEBUG - if (DHD_GLOM_ON()) { - prhex("SUPERFRAME", PKTDATA(osh, pfirst), - MIN(PKTLEN(osh, pfirst), 48)); - } -#endif - - - /* Validate the superframe header */ - dptr = (uint8 *)PKTDATA(osh, pfirst); - sublen = ltoh16_ua(dptr); - check = ltoh16_ua(dptr + sizeof(uint16)); - - chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); - seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); - bus->nextlen = dptr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; - if ((bus->nextlen << 4) > MAX_RX_DATASZ) { - DHD_INFO(("%s: got frame w/nextlen too large (%d) seq %d\n", - __FUNCTION__, bus->nextlen, seq)); - bus->nextlen = 0; - } - doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); - txmax = SDPCM_WINDOW_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); - - errcode = 0; - if ((uint16)~(sublen^check)) { - DHD_ERROR(("%s (superframe): HW hdr error: len/check 0x%04x/0x%04x\n", - __FUNCTION__, sublen, check)); - errcode = -1; - } else if (ROUNDUP(sublen, bus->blocksize) != dlen) { - DHD_ERROR(("%s (superframe): len 0x%04x, rounded 0x%04x, expect 0x%04x\n", - __FUNCTION__, sublen, ROUNDUP(sublen, bus->blocksize), dlen)); - errcode = -1; - } else if (SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]) != SDPCM_GLOM_CHANNEL) { - DHD_ERROR(("%s (superframe): bad channel %d\n", __FUNCTION__, - SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]))); - errcode = -1; - } else if (SDPCM_GLOMDESC(&dptr[SDPCM_FRAMETAG_LEN])) { - DHD_ERROR(("%s (superframe): got second descriptor?\n", __FUNCTION__)); - errcode = -1; - } else if ((doff < SDPCM_HDRLEN) || - (doff > (PKTLEN(osh, pfirst) - SDPCM_HDRLEN))) { - DHD_ERROR(("%s (superframe): Bad data offset %d: HW %d pkt %d min %d\n", - __FUNCTION__, doff, sublen, PKTLEN(osh, pfirst), SDPCM_HDRLEN)); - errcode = -1; - } - - /* Check sequence number of superframe SW header */ - if (rxseq != seq) { - DHD_INFO(("%s: (superframe) rx_seq %d, expected %d\n", - __FUNCTION__, seq, rxseq)); - bus->rx_badseq++; - rxseq = seq; - } - - /* Check window for sanity */ - if ((uint8)(txmax - bus->tx_seq) > 0x40) { - DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", - __FUNCTION__, txmax, bus->tx_seq)); - txmax = bus->tx_max; - } - bus->tx_max = txmax; - - /* Remove superframe header, remember offset */ - PKTPULL(osh, pfirst, doff); - sfdoff = doff; - - /* Validate all the subframe headers */ - for (num = 0, pnext = pfirst; pnext && !errcode; - num++, pnext = PKTNEXT(osh, pnext)) { - dptr = (uint8 *)PKTDATA(osh, pnext); - dlen = (uint16)PKTLEN(osh, pnext); - sublen = ltoh16_ua(dptr); - check = ltoh16_ua(dptr + sizeof(uint16)); - chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); - doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); -#ifdef DHD_DEBUG - if (DHD_GLOM_ON()) { - prhex("subframe", dptr, 32); - } -#endif - - if ((uint16)~(sublen^check)) { - DHD_ERROR(("%s (subframe %d): HW hdr error: " - "len/check 0x%04x/0x%04x\n", - __FUNCTION__, num, sublen, check)); - errcode = -1; - } else if ((sublen > dlen) || (sublen < SDPCM_HDRLEN)) { - DHD_ERROR(("%s (subframe %d): length mismatch: " - "len 0x%04x, expect 0x%04x\n", - __FUNCTION__, num, sublen, dlen)); - errcode = -1; - } else if ((chan != SDPCM_DATA_CHANNEL) && - (chan != SDPCM_EVENT_CHANNEL)) { - DHD_ERROR(("%s (subframe %d): bad channel %d\n", - __FUNCTION__, num, chan)); - errcode = -1; - } else if ((doff < SDPCM_HDRLEN) || (doff > sublen)) { - DHD_ERROR(("%s (subframe %d): Bad data offset %d: HW %d min %d\n", - __FUNCTION__, num, doff, sublen, SDPCM_HDRLEN)); - errcode = -1; - } - } - - if (errcode) { - /* Terminate frame on error, request a couple retries */ - if (bus->glomerr++ < 3) { - /* Restore superframe header space */ - PKTPUSH(osh, pfirst, sfdoff); - dhdsdio_rxfail(bus, TRUE, TRUE); - } else { - bus->glomerr = 0; - dhdsdio_rxfail(bus, TRUE, FALSE); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(osh, bus->glom, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - bus->rxglomfail++; - bus->glom = NULL; - } - bus->nextlen = 0; - return 0; - } - - /* Basic SD framing looks ok - process each packet (header) */ - bus->glom = NULL; - plast = NULL; - - dhd_os_sdlock_rxq(bus->dhd); - for (num = 0; pfirst; rxseq++, pfirst = pnext) { - pnext = PKTNEXT(osh, pfirst); - PKTSETNEXT(osh, pfirst, NULL); - - dptr = (uint8 *)PKTDATA(osh, pfirst); - sublen = ltoh16_ua(dptr); - chan = SDPCM_PACKET_CHANNEL(&dptr[SDPCM_FRAMETAG_LEN]); - seq = SDPCM_PACKET_SEQUENCE(&dptr[SDPCM_FRAMETAG_LEN]); - doff = SDPCM_DOFFSET_VALUE(&dptr[SDPCM_FRAMETAG_LEN]); - - DHD_GLOM(("%s: Get subframe %d, %p(%p/%d), sublen %d chan %d seq %d\n", - __FUNCTION__, num, pfirst, PKTDATA(osh, pfirst), - PKTLEN(osh, pfirst), sublen, chan, seq)); - - ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL)); - - if (rxseq != seq) { - DHD_GLOM(("%s: rx_seq %d, expected %d\n", - __FUNCTION__, seq, rxseq)); - bus->rx_badseq++; - rxseq = seq; - } - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_DATA_ON()) { - prhex("Rx Subframe Data", dptr, dlen); - } -#endif - - PKTSETLEN(osh, pfirst, sublen); - PKTPULL(osh, pfirst, doff); - - reorder_info_len = sizeof(reorder_info_buf); - - if (PKTLEN(osh, pfirst) == 0) { - PKTFREE(bus->dhd->osh, pfirst, FALSE); - if (plast) { - PKTSETNEXT(osh, plast, pnext); - } - continue; - } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pfirst, reorder_info_buf, - &reorder_info_len) != 0) { - DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); - bus->dhd->rx_errors++; - PKTFREE(osh, pfirst, FALSE); - if (plast) { - PKTSETNEXT(osh, plast, pnext); - } - continue; - } - if (reorder_info_len) { - uint32 free_buf_count; - void *ppfirst; - - ppfirst = pfirst; - /* Reordering info from the firmware */ - dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, - reorder_info_len, &ppfirst, &free_buf_count); - - if (free_buf_count == 0) { - if (plast) { - PKTSETNEXT(osh, plast, pnext); - } - continue; - } - else { - void *temp; - - /* go to the end of the chain and attach the pnext there */ - temp = ppfirst; - while (PKTNEXT(osh, temp) != NULL) { - temp = PKTNEXT(osh, temp); - } - pfirst = temp; - if (list_tail[ifidx] == NULL) { - list_head[ifidx] = ppfirst; - list_tail[ifidx] = pfirst; - } - else { - PKTSETNEXT(osh, list_tail[ifidx], ppfirst); - list_tail[ifidx] = pfirst; - } - plast = pfirst; - } - - num += (uint8)free_buf_count; - } - else { - /* this packet will go up, link back into chain and count it */ - plast = pfirst; - if (list_tail[ifidx] == NULL) { - list_head[ifidx] = list_tail[ifidx] = pfirst; - } - else { - PKTSETNEXT(osh, list_tail[ifidx], pfirst); - list_tail[ifidx] = pfirst; - } - num++; - } -#ifdef DHD_DEBUG - if (DHD_GLOM_ON()) { - DHD_GLOM(("%s subframe %d to stack, %p(%p/%d) nxt/lnk %p/%p\n", - __FUNCTION__, num, pfirst, - PKTDATA(osh, pfirst), PKTLEN(osh, pfirst), - PKTNEXT(osh, pfirst), PKTLINK(pfirst))); - prhex("", (uint8 *)PKTDATA(osh, pfirst), - MIN(PKTLEN(osh, pfirst), 32)); - } -#endif /* DHD_DEBUG */ - } - dhd_os_sdunlock_rxq(bus->dhd); - for (idx = 0; idx < DHD_MAX_IFS; idx++) { - if (list_head[idx]) { - void *temp; - uint8 cnt = 0; - temp = list_head[idx]; - do { - temp = PKTNEXT(osh, temp); - cnt++; - } while (temp); - if (cnt) { - dhd_os_sdunlock(bus->dhd); - dhd_rx_frame(bus->dhd, idx, list_head[idx], cnt, 0); - dhd_os_sdlock(bus->dhd); - } - } - } - bus->rxglomframes++; - bus->rxglompkts += num; - } - return num; -} - - -/* Return TRUE if there may be more frames to read */ -static uint -dhdsdio_readframes(dhd_bus_t *bus, uint maxframes, bool *finished) -{ - osl_t *osh = bus->dhd->osh; - bcmsdh_info_t *sdh = bus->sdh; - - uint16 len, check; /* Extracted hardware header fields */ - uint8 chan, seq, doff; /* Extracted software header fields */ - uint8 fcbits; /* Extracted fcbits from software header */ - uint8 delta; - - void *pkt; /* Packet for event or data frames */ - uint16 pad; /* Number of pad bytes to read */ - uint16 rdlen; /* Total number of bytes to read */ - uint8 rxseq; /* Next sequence number to expect */ - uint rxleft = 0; /* Remaining number of frames allowed */ - int sdret; /* Return code from bcmsdh calls */ - uint8 txmax; /* Maximum tx sequence offered */ - bool len_consistent; /* Result of comparing readahead len and len from hw-hdr */ - uint8 *rxbuf; - int ifidx = 0; - uint rxcount = 0; /* Total frames read */ - uchar reorder_info_buf[WLHOST_REORDERDATA_TOTLEN]; - uint reorder_info_len; - uint pkt_count; - -#if defined(DHD_DEBUG) || defined(SDTEST) - bool sdtest = FALSE; /* To limit message spew from test mode */ -#endif - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - bus->readframes = TRUE; - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: KSO off\n", __FUNCTION__)); - bus->readframes = FALSE; - return 0; - } - - ASSERT(maxframes); - -#ifdef SDTEST - /* Allow pktgen to override maxframes */ - if (bus->pktgen_count && (bus->pktgen_mode == DHD_PKTGEN_RECV)) { - maxframes = bus->pktgen_count; - sdtest = TRUE; - } -#endif - - /* Not finished unless we encounter no more frames indication */ - *finished = FALSE; - - - for (rxseq = bus->rx_seq, rxleft = maxframes; - !bus->rxskip && rxleft && bus->dhd->busstate != DHD_BUS_DOWN; - rxseq++, rxleft--) { - -#ifdef DHDTHREAD - /* tx more to improve rx performance */ - if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && - pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) { - dhdsdio_sendfromq(bus, dhd_txbound); - } -#endif /* DHDTHREAD */ - - /* Handle glomming separately */ - if (bus->glom || bus->glomd) { - uint8 cnt; - DHD_GLOM(("%s: calling rxglom: glomd %p, glom %p\n", - __FUNCTION__, bus->glomd, bus->glom)); - cnt = dhdsdio_rxglom(bus, rxseq); - DHD_GLOM(("%s: rxglom returned %d\n", __FUNCTION__, cnt)); - rxseq += cnt - 1; - rxleft = (rxleft > cnt) ? (rxleft - cnt) : 1; - continue; - } - - /* Try doing single read if we can */ - if (dhd_readahead && bus->nextlen) { - uint16 nextlen = bus->nextlen; - bus->nextlen = 0; - - if (bus->bus == SPI_BUS) { - rdlen = len = nextlen; - } - else { - rdlen = len = nextlen << 4; - - /* Pad read to blocksize for efficiency */ - if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { - pad = bus->blocksize - (rdlen % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize) && - ((rdlen + pad + firstread) < MAX_RX_DATASZ)) - rdlen += pad; - } else if (rdlen % DHD_SDALIGN) { - rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); - } - } - - /* We use bus->rxctl buffer in WinXP for initial control pkt receives. - * Later we use buffer-poll for data as well as control packets. - * This is required because dhd receives full frame in gSPI unlike SDIO. - * After the frame is received we have to distinguish whether it is data - * or non-data frame. - */ - /* Allocate a packet buffer */ - dhd_os_sdlock_rxq(bus->dhd); - if (!(pkt = PKTGET(osh, rdlen + DHD_SDALIGN, FALSE))) { - if (bus->bus == SPI_BUS) { - bus->usebufpool = FALSE; - bus->rxctl = bus->rxbuf; - if (dhd_alignctl) { - bus->rxctl += firstread; - if ((pad = ((uintptr)bus->rxctl % DHD_SDALIGN))) - bus->rxctl += (DHD_SDALIGN - pad); - bus->rxctl -= firstread; - } - ASSERT(bus->rxctl >= bus->rxbuf); - rxbuf = bus->rxctl; - /* Read the entire frame */ - sdret = dhd_bcmsdh_recv_buf(bus, - bcmsdh_cur_sbwad(sdh), - SDIO_FUNC_2, - F2SYNC, rxbuf, rdlen, - NULL, NULL, NULL); - bus->f2rxdata++; - ASSERT(sdret != BCME_PENDING); - - - /* Control frame failures need retransmission */ - if (sdret < 0) { - DHD_ERROR(("%s: read %d control bytes failed: %d\n", - __FUNCTION__, rdlen, sdret)); - /* dhd.rx_ctlerrs is higher level */ - bus->rxc_errors++; - dhd_os_sdunlock_rxq(bus->dhd); - dhdsdio_rxfail(bus, TRUE, - (bus->bus == SPI_BUS) ? FALSE : TRUE); - continue; - } - } else { - /* Give up on data, request rtx of events */ - DHD_ERROR(("%s (nextlen): PKTGET failed: len %d rdlen %d " - "expected rxseq %d\n", - __FUNCTION__, len, rdlen, rxseq)); - /* Just go try again w/normal header read */ - dhd_os_sdunlock_rxq(bus->dhd); - continue; - } - } else { - if (bus->bus == SPI_BUS) - bus->usebufpool = TRUE; - - ASSERT(!PKTLINK(pkt)); - PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); - rxbuf = (uint8 *)PKTDATA(osh, pkt); - /* Read the entire frame */ - sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), - SDIO_FUNC_2, - F2SYNC, rxbuf, rdlen, - pkt, NULL, NULL); - bus->f2rxdata++; - ASSERT(sdret != BCME_PENDING); - - if (sdret < 0) { - DHD_ERROR(("%s (nextlen): read %d bytes failed: %d\n", - __FUNCTION__, rdlen, sdret)); - PKTFREE(bus->dhd->osh, pkt, FALSE); - bus->dhd->rx_errors++; - dhd_os_sdunlock_rxq(bus->dhd); - /* Force retry w/normal header read. Don't attempt NAK for - * gSPI - */ - dhdsdio_rxfail(bus, TRUE, - (bus->bus == SPI_BUS) ? FALSE : TRUE); - continue; - } - } - dhd_os_sdunlock_rxq(bus->dhd); - - /* Now check the header */ - bcopy(rxbuf, bus->rxhdr, SDPCM_HDRLEN); - - /* Extract hardware header fields */ - len = ltoh16_ua(bus->rxhdr); - check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); - - /* All zeros means readahead info was bad */ - if (!(len|check)) { - DHD_INFO(("%s (nextlen): read zeros in HW header???\n", - __FUNCTION__)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - GSPI_PR55150_BAILOUT; - continue; - } - - /* Validate check bytes */ - if ((uint16)~(len^check)) { - DHD_ERROR(("%s (nextlen): HW hdr error: nextlen/len/check" - " 0x%04x/0x%04x/0x%04x\n", __FUNCTION__, nextlen, - len, check)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - bus->rx_badhdr++; - dhdsdio_rxfail(bus, FALSE, FALSE); - GSPI_PR55150_BAILOUT; - continue; - } - - /* Validate frame length */ - if (len < SDPCM_HDRLEN) { - DHD_ERROR(("%s (nextlen): HW hdr length invalid: %d\n", - __FUNCTION__, len)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - GSPI_PR55150_BAILOUT; - continue; - } - - /* Check for consistency with readahead info */ - len_consistent = (nextlen != (ROUNDUP(len, 16) >> 4)); - if (len_consistent) { - /* Mismatch, force retry w/normal header (may be >4K) */ - DHD_ERROR(("%s (nextlen): mismatch, nextlen %d len %d rnd %d; " - "expected rxseq %d\n", - __FUNCTION__, nextlen, len, ROUNDUP(len, 16), rxseq)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - dhdsdio_rxfail(bus, TRUE, (bus->bus == SPI_BUS) ? FALSE : TRUE); - GSPI_PR55150_BAILOUT; - continue; - } - - - /* Extract software header fields */ - chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - bus->nextlen = - bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; - if ((bus->nextlen << 4) > MAX_RX_DATASZ) { - DHD_INFO(("%s (nextlen): got frame w/nextlen too large" - " (%d), seq %d\n", __FUNCTION__, bus->nextlen, - seq)); - bus->nextlen = 0; - } - - bus->dhd->rx_readahead_cnt ++; - /* Handle Flow Control */ - fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - delta = 0; - if (~bus->flowcontrol & fcbits) { - bus->fc_xoff++; - delta = 1; - } - if (bus->flowcontrol & ~fcbits) { - bus->fc_xon++; - delta = 1; - } - - if (delta) { - bus->fc_rcvd++; - bus->flowcontrol = fcbits; - } - - /* Check and update sequence number */ - if (rxseq != seq) { - DHD_INFO(("%s (nextlen): rx_seq %d, expected %d\n", - __FUNCTION__, seq, rxseq)); - bus->rx_badseq++; - rxseq = seq; - } - - /* Check window for sanity */ - if ((uint8)(txmax - bus->tx_seq) > 0x40) { - DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", - __FUNCTION__, txmax, bus->tx_seq)); - txmax = bus->tx_max; - } - bus->tx_max = txmax; - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_DATA_ON()) { - prhex("Rx Data", rxbuf, len); - } else if (DHD_HDRS_ON()) { - prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); - } -#endif - - if (chan == SDPCM_CONTROL_CHANNEL) { - if (bus->bus == SPI_BUS) { - dhdsdio_read_control(bus, rxbuf, len, doff); - if (bus->usebufpool) { - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - } - continue; - } else { - DHD_ERROR(("%s (nextlen): readahead on control" - " packet %d?\n", __FUNCTION__, seq)); - /* Force retry w/normal header read */ - bus->nextlen = 0; - dhdsdio_rxfail(bus, FALSE, TRUE); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - continue; - } - } - - if ((bus->bus == SPI_BUS) && !bus->usebufpool) { - DHD_ERROR(("Received %d bytes on %d channel. Running out of " - "rx pktbuf's or not yet malloced.\n", len, chan)); - continue; - } - - /* Validate data offset */ - if ((doff < SDPCM_HDRLEN) || (doff > len)) { - DHD_ERROR(("%s (nextlen): bad data offset %d: HW len %d min %d\n", - __FUNCTION__, doff, len, SDPCM_HDRLEN)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE2(); - dhd_os_sdunlock_rxq(bus->dhd); - ASSERT(0); - dhdsdio_rxfail(bus, FALSE, FALSE); - continue; - } - - /* All done with this one -- now deliver the packet */ - goto deliver; - } - /* gSPI frames should not be handled in fractions */ - if (bus->bus == SPI_BUS) { - break; - } - - /* Read frame header (hardware and software) */ - sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - bus->rxhdr, firstread, NULL, NULL, NULL); - bus->f2rxhdrs++; - ASSERT(sdret != BCME_PENDING); - - if (sdret < 0) { - DHD_ERROR(("%s: RXHEADER FAILED: %d\n", __FUNCTION__, sdret)); - bus->rx_hdrfail++; - dhdsdio_rxfail(bus, TRUE, TRUE); - continue; - } - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() || DHD_HDRS_ON()) { - prhex("RxHdr", bus->rxhdr, SDPCM_HDRLEN); - } -#endif - - /* Extract hardware header fields */ - len = ltoh16_ua(bus->rxhdr); - check = ltoh16_ua(bus->rxhdr + sizeof(uint16)); - - /* All zeros means no more frames */ - if (!(len|check)) { - *finished = TRUE; - break; - } - - /* Validate check bytes */ - if ((uint16)~(len^check)) { - DHD_ERROR(("%s: HW hdr error: len/check 0x%04x/0x%04x\n", - __FUNCTION__, len, check)); - bus->rx_badhdr++; - dhdsdio_rxfail(bus, FALSE, FALSE); - continue; - } - - /* Validate frame length */ - if (len < SDPCM_HDRLEN) { - DHD_ERROR(("%s: HW hdr length invalid: %d\n", __FUNCTION__, len)); - continue; - } - - /* Extract software header fields */ - chan = SDPCM_PACKET_CHANNEL(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - seq = SDPCM_PACKET_SEQUENCE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - doff = SDPCM_DOFFSET_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - txmax = SDPCM_WINDOW_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - /* Validate data offset */ - if ((doff < SDPCM_HDRLEN) || (doff > len)) { - DHD_ERROR(("%s: Bad data offset %d: HW len %d, min %d seq %d\n", - __FUNCTION__, doff, len, SDPCM_HDRLEN, seq)); - bus->rx_badhdr++; - ASSERT(0); - dhdsdio_rxfail(bus, FALSE, FALSE); - continue; - } - - /* Save the readahead length if there is one */ - bus->nextlen = bus->rxhdr[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET]; - if ((bus->nextlen << 4) > MAX_RX_DATASZ) { - DHD_INFO(("%s (nextlen): got frame w/nextlen too large (%d), seq %d\n", - __FUNCTION__, bus->nextlen, seq)); - bus->nextlen = 0; - } - - /* Handle Flow Control */ - fcbits = SDPCM_FCMASK_VALUE(&bus->rxhdr[SDPCM_FRAMETAG_LEN]); - - delta = 0; - if (~bus->flowcontrol & fcbits) { - bus->fc_xoff++; - delta = 1; - } - if (bus->flowcontrol & ~fcbits) { - bus->fc_xon++; - delta = 1; - } - - if (delta) { - bus->fc_rcvd++; - bus->flowcontrol = fcbits; - } - - /* Check and update sequence number */ - if (rxseq != seq) { - DHD_INFO(("%s: rx_seq %d, expected %d\n", __FUNCTION__, seq, rxseq)); - bus->rx_badseq++; - rxseq = seq; - } - - /* Check window for sanity */ - if ((uint8)(txmax - bus->tx_seq) > 0x40) { - DHD_ERROR(("%s: got unlikely tx max %d with tx_seq %d\n", - __FUNCTION__, txmax, bus->tx_seq)); - txmax = bus->tx_max; - } - bus->tx_max = txmax; - - /* Call a separate function for control frames */ - if (chan == SDPCM_CONTROL_CHANNEL) { - dhdsdio_read_control(bus, bus->rxhdr, len, doff); - continue; - } - - ASSERT((chan == SDPCM_DATA_CHANNEL) || (chan == SDPCM_EVENT_CHANNEL) || - (chan == SDPCM_TEST_CHANNEL) || (chan == SDPCM_GLOM_CHANNEL)); - - /* Length to read */ - rdlen = (len > firstread) ? (len - firstread) : 0; - - /* May pad read to blocksize for efficiency */ - if (bus->roundup && bus->blocksize && (rdlen > bus->blocksize)) { - pad = bus->blocksize - (rdlen % bus->blocksize); - if ((pad <= bus->roundup) && (pad < bus->blocksize) && - ((rdlen + pad + firstread) < MAX_RX_DATASZ)) - rdlen += pad; - } else if (rdlen % DHD_SDALIGN) { - rdlen += DHD_SDALIGN - (rdlen % DHD_SDALIGN); - } - - /* Satisfy length-alignment requirements */ - if (forcealign && (rdlen & (ALIGNMENT - 1))) - rdlen = ROUNDUP(rdlen, ALIGNMENT); - - if ((rdlen + firstread) > MAX_RX_DATASZ) { - /* Too long -- skip this frame */ - DHD_ERROR(("%s: too long: len %d rdlen %d\n", __FUNCTION__, len, rdlen)); - bus->dhd->rx_errors++; bus->rx_toolong++; - dhdsdio_rxfail(bus, FALSE, FALSE); - continue; - } - - dhd_os_sdlock_rxq(bus->dhd); - if (!(pkt = PKTGET(osh, (rdlen + firstread + DHD_SDALIGN), FALSE))) { - /* Give up on data, request rtx of events */ - DHD_ERROR(("%s: PKTGET failed: rdlen %d chan %d\n", - __FUNCTION__, rdlen, chan)); - bus->dhd->rx_dropped++; - dhd_os_sdunlock_rxq(bus->dhd); - dhdsdio_rxfail(bus, FALSE, RETRYCHAN(chan)); - continue; - } - dhd_os_sdunlock_rxq(bus->dhd); - - ASSERT(!PKTLINK(pkt)); - - /* Leave room for what we already read, and align remainder */ - ASSERT(firstread < (PKTLEN(osh, pkt))); - PKTPULL(osh, pkt, firstread); - PKTALIGN(osh, pkt, rdlen, DHD_SDALIGN); - - /* Read the remaining frame data */ - sdret = dhd_bcmsdh_recv_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - ((uint8 *)PKTDATA(osh, pkt)), rdlen, pkt, NULL, NULL); - bus->f2rxdata++; - ASSERT(sdret != BCME_PENDING); - - if (sdret < 0) { - DHD_ERROR(("%s: read %d %s bytes failed: %d\n", __FUNCTION__, rdlen, - ((chan == SDPCM_EVENT_CHANNEL) ? "event" : - ((chan == SDPCM_DATA_CHANNEL) ? "data" : "test")), sdret)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - bus->dhd->rx_errors++; - dhdsdio_rxfail(bus, TRUE, RETRYCHAN(chan)); - continue; - } - - /* Copy the already-read portion */ - PKTPUSH(osh, pkt, firstread); - bcopy(bus->rxhdr, PKTDATA(osh, pkt), firstread); - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_DATA_ON()) { - prhex("Rx Data", PKTDATA(osh, pkt), len); - } -#endif - -deliver: - /* Save superframe descriptor and allocate packet frame */ - if (chan == SDPCM_GLOM_CHANNEL) { - if (SDPCM_GLOMDESC(&bus->rxhdr[SDPCM_FRAMETAG_LEN])) { - DHD_GLOM(("%s: got glom descriptor, %d bytes:\n", - __FUNCTION__, len)); -#ifdef DHD_DEBUG - if (DHD_GLOM_ON()) { - prhex("Glom Data", PKTDATA(osh, pkt), len); - } -#endif - PKTSETLEN(osh, pkt, len); - ASSERT(doff == SDPCM_HDRLEN); - PKTPULL(osh, pkt, SDPCM_HDRLEN); - bus->glomd = pkt; - } else { - DHD_ERROR(("%s: glom superframe w/o descriptor!\n", __FUNCTION__)); - dhdsdio_rxfail(bus, FALSE, FALSE); - } - continue; - } - - /* Fill in packet len and prio, deliver upward */ - PKTSETLEN(osh, pkt, len); - PKTPULL(osh, pkt, doff); - -#ifdef SDTEST - /* Test channel packets are processed separately */ - if (chan == SDPCM_TEST_CHANNEL) { - dhdsdio_testrcv(bus, pkt, seq); - continue; - } -#endif /* SDTEST */ - - if (PKTLEN(osh, pkt) == 0) { - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - continue; - } else if (dhd_prot_hdrpull(bus->dhd, &ifidx, pkt, reorder_info_buf, - &reorder_info_len) != 0) { - DHD_ERROR(("%s: rx protocol error\n", __FUNCTION__)); - dhd_os_sdlock_rxq(bus->dhd); - PKTFREE(bus->dhd->osh, pkt, FALSE); - dhd_os_sdunlock_rxq(bus->dhd); - bus->dhd->rx_errors++; - continue; - } - if (reorder_info_len) { - /* Reordering info from the firmware */ - dhd_process_pkt_reorder_info(bus->dhd, reorder_info_buf, reorder_info_len, - &pkt, &pkt_count); - if (pkt_count == 0) - continue; - } - else - pkt_count = 1; - - - /* Unlock during rx call */ - dhd_os_sdunlock(bus->dhd); - dhd_rx_frame(bus->dhd, ifidx, pkt, pkt_count, chan); - dhd_os_sdlock(bus->dhd); - } - rxcount = maxframes - rxleft; -#ifdef DHD_DEBUG - /* Message if we hit the limit */ - if (!rxleft && !sdtest) - DHD_DATA(("%s: hit rx limit of %d frames\n", __FUNCTION__, maxframes)); - else -#endif /* DHD_DEBUG */ - DHD_DATA(("%s: processed %d frames\n", __FUNCTION__, rxcount)); - /* Back off rxseq if awaiting rtx, update rx_seq */ - if (bus->rxskip) - rxseq--; - bus->rx_seq = rxseq; - bus->readframes = FALSE; - - return rxcount; -} - -static uint32 -dhdsdio_hostmail(dhd_bus_t *bus) -{ - sdpcmd_regs_t *regs = bus->regs; - uint32 intstatus = 0; - uint32 hmb_data; - uint8 fcbits; - uint retries = 0; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Read mailbox data and ack that we did so */ - R_SDREG(hmb_data, ®s->tohostmailboxdata, retries); - if (retries <= retry_limit) - W_SDREG(SMB_INT_ACK, ®s->tosbmailbox, retries); - bus->f1regdata += 2; - - /* Dongle recomposed rx frames, accept them again */ - if (hmb_data & HMB_DATA_NAKHANDLED) { - DHD_INFO(("Dongle reports NAK handled, expect rtx of %d\n", bus->rx_seq)); - if (!bus->rxskip) { - DHD_ERROR(("%s: unexpected NAKHANDLED!\n", __FUNCTION__)); - } - bus->rxskip = FALSE; - intstatus |= FRAME_AVAIL_MASK(bus); - } - - /* - * DEVREADY does not occur with gSPI. - */ - if (hmb_data & (HMB_DATA_DEVREADY | HMB_DATA_FWREADY)) { - bus->sdpcm_ver = (hmb_data & HMB_DATA_VERSION_MASK) >> HMB_DATA_VERSION_SHIFT; - if (bus->sdpcm_ver != SDPCM_PROT_VERSION) - DHD_ERROR(("Version mismatch, dongle reports %d, expecting %d\n", - bus->sdpcm_ver, SDPCM_PROT_VERSION)); - else - DHD_INFO(("Dongle ready, protocol version %d\n", bus->sdpcm_ver)); - /* make sure for the SDIO_DEVICE_RXDATAINT_MODE_1 corecontrol is proper */ - if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && - (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) { - uint32 val; - - val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); - val &= ~CC_XMTDATAAVAIL_MODE; - val |= CC_XMTDATAAVAIL_CTRL; - W_REG(bus->dhd->osh, &bus->regs->corecontrol, val); - - val = R_REG(bus->dhd->osh, &bus->regs->corecontrol); - } - -#ifdef DHD_DEBUG - /* Retrieve console state address now that firmware should have updated it */ - // Kent: tempoprary rollback - firmware should be modified for a correct dconpoll operation - // if(dhd_console_ms > 0) - { - sdpcm_shared_t shared; - if (dhdsdio_readshared(bus, &shared) == 0) - bus->console_addr = shared.console_addr; - } -#endif /* DHD_DEBUG */ - } - - /* - * Flow Control has been moved into the RX headers and this out of band - * method isn't used any more. Leave this here for possibly remaining backward - * compatible with older dongles - */ - if (hmb_data & HMB_DATA_FC) { - fcbits = (hmb_data & HMB_DATA_FCDATA_MASK) >> HMB_DATA_FCDATA_SHIFT; - - if (fcbits & ~bus->flowcontrol) - bus->fc_xoff++; - if (bus->flowcontrol & ~fcbits) - bus->fc_xon++; - - bus->fc_rcvd++; - bus->flowcontrol = fcbits; - } - -#ifdef DHD_DEBUG - /* At least print a message if FW halted */ - if (hmb_data & HMB_DATA_FWHALT) { - DHD_ERROR(("INTERNAL ERROR: FIRMWARE HALTED\n")); - dhdsdio_checkdied(bus, NULL, 0); - } -#endif /* DHD_DEBUG */ - - /* Shouldn't be any others */ - if (hmb_data & ~(HMB_DATA_DEVREADY | - HMB_DATA_FWHALT | - HMB_DATA_NAKHANDLED | - HMB_DATA_FC | - HMB_DATA_FWREADY | - HMB_DATA_FCDATA_MASK | - HMB_DATA_VERSION_MASK)) { - DHD_ERROR(("Unknown mailbox data content: 0x%02x\n", hmb_data)); - } - - return intstatus; -} - -static bool -dhdsdio_dpc(dhd_bus_t *bus) -{ - bcmsdh_info_t *sdh = bus->sdh; - sdpcmd_regs_t *regs = bus->regs; - uint32 intstatus, newstatus = 0; - uint retries = 0; - uint rxlimit = dhd_rxbound; /* Rx frames to read before resched */ - uint txlimit = dhd_txbound; /* Tx frames to send before resched */ - uint framecnt = 0; /* Temporary counter of tx/rx frames */ - bool rxdone = TRUE; /* Flag for no more read data */ - bool resched = FALSE; /* Flag indicating resched wanted */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s: Bus down, ret\n", __FUNCTION__)); - bus->intstatus = 0; - return 0; - } - - /* Start with leftover status bits */ - intstatus = bus->intstatus; - - dhd_os_sdlock(bus->dhd); - - if (!SLPAUTO_ENAB(bus) && !KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - goto exit; - } - - /* If waiting for HTAVAIL, check status */ - if (!SLPAUTO_ENAB(bus) && (bus->clkstate == CLK_PENDING)) { - int err; - uint8 clkctl, devctl = 0; - -#ifdef DHD_DEBUG - /* Check for inconsistent device control */ - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - if (err) { - DHD_ERROR(("%s: error reading DEVCTL: %d\n", __FUNCTION__, err)); - bus->dhd->busstate = DHD_BUS_DOWN; - } else { - ASSERT(devctl & SBSDIO_DEVCTL_CA_INT_ONLY); - } -#endif /* DHD_DEBUG */ - - /* Read CSR, if clock on switch to AVAIL, else ignore */ - clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - if (err) { - DHD_ERROR(("%s: error reading CSR: %d\n", __FUNCTION__, err)); - bus->dhd->busstate = DHD_BUS_DOWN; - } - - DHD_INFO(("DPC: PENDING, devctl 0x%02x clkctl 0x%02x\n", devctl, clkctl)); - - if (SBSDIO_HTAV(clkctl)) { - devctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, &err); - if (err) { - DHD_ERROR(("%s: error reading DEVCTL: %d\n", - __FUNCTION__, err)); - bus->dhd->busstate = DHD_BUS_DOWN; - } - devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_DEVICE_CTL, devctl, &err); - if (err) { - DHD_ERROR(("%s: error writing DEVCTL: %d\n", - __FUNCTION__, err)); - bus->dhd->busstate = DHD_BUS_DOWN; - } - bus->clkstate = CLK_AVAIL; - } else { - goto clkwait; - } - } - - BUS_WAKE(bus); - - /* Make sure backplane clock is on */ - dhdsdio_clkctl(bus, CLK_AVAIL, TRUE); - if (bus->clkstate != CLK_AVAIL) - goto clkwait; - - /* Pending interrupt indicates new device status */ - if (bus->ipend) { - bus->ipend = FALSE; - R_SDREG(newstatus, ®s->intstatus, retries); - bus->f1regdata++; - if (bcmsdh_regfail(bus->sdh)) - newstatus = 0; - newstatus &= bus->hostintmask; - bus->fcstate = !!(newstatus & I_HMB_FC_STATE); - if (newstatus) { - bus->f1regdata++; - if ((bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_0) && - (newstatus == I_XMTDATA_AVAIL)) { - } - else - W_SDREG(newstatus, ®s->intstatus, retries); - } - } - - /* Merge new bits with previous */ - intstatus |= newstatus; - bus->intstatus = 0; - - /* Handle flow-control change: read new state in case our ack - * crossed another change interrupt. If change still set, assume - * FC ON for safety, let next loop through do the debounce. - */ - if (intstatus & I_HMB_FC_CHANGE) { - intstatus &= ~I_HMB_FC_CHANGE; - W_SDREG(I_HMB_FC_CHANGE, ®s->intstatus, retries); - R_SDREG(newstatus, ®s->intstatus, retries); - bus->f1regdata += 2; - bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); - intstatus |= (newstatus & bus->hostintmask); - } - - /* Just being here means nothing more to do for chipactive */ - if (intstatus & I_CHIPACTIVE) { - /* ASSERT(bus->clkstate == CLK_AVAIL); */ - intstatus &= ~I_CHIPACTIVE; - } - - /* Handle host mailbox indication */ - if (intstatus & I_HMB_HOST_INT) { - intstatus &= ~I_HMB_HOST_INT; - intstatus |= dhdsdio_hostmail(bus); - } - - /* Generally don't ask for these, can get CRC errors... */ - if (intstatus & I_WR_OOSYNC) { - DHD_ERROR(("Dongle reports WR_OOSYNC\n")); - intstatus &= ~I_WR_OOSYNC; - } - - if (intstatus & I_RD_OOSYNC) { - DHD_ERROR(("Dongle reports RD_OOSYNC\n")); - intstatus &= ~I_RD_OOSYNC; - } - - if (intstatus & I_SBINT) { - DHD_ERROR(("Dongle reports SBINT\n")); - intstatus &= ~I_SBINT; - } - - /* Would be active due to wake-wlan in gSPI */ - if (intstatus & I_CHIPACTIVE) { - DHD_INFO(("Dongle reports CHIPACTIVE\n")); - intstatus &= ~I_CHIPACTIVE; - } - - /* Ignore frame indications if rxskip is set */ - if (bus->rxskip) { - intstatus &= ~FRAME_AVAIL_MASK(bus); - } - - /* On frame indication, read available frames */ - if (PKT_AVAILABLE(bus, intstatus)) { - framecnt = dhdsdio_readframes(bus, rxlimit, &rxdone); - if (rxdone || bus->rxskip) - intstatus &= ~FRAME_AVAIL_MASK(bus); - rxlimit -= MIN(framecnt, rxlimit); - } - - /* Keep still-pending events for next scheduling */ - bus->intstatus = intstatus; - -clkwait: - /* Re-enable interrupts to detect new device events (mailbox, rx frame) - * or clock availability. (Allows tx loop to check ipend if desired.) - * (Unless register access seems hosed, as we may not be able to ACK...) - */ - if (bus->intr && bus->intdis && !bcmsdh_regfail(sdh)) { - DHD_INTR(("%s: enable SDIO interrupts, rxdone %d framecnt %d\n", - __FUNCTION__, rxdone, framecnt)); - bus->intdis = FALSE; -#if defined(OOB_INTR_ONLY) - bcmsdh_oob_intr_set(1); -#endif /* (OOB_INTR_ONLY) */ - bcmsdh_intr_enable(sdh); - } - -#if defined(OOB_INTR_ONLY) && !defined(HW_OOB) - /* In case of SW-OOB(using edge trigger), - * Check interrupt status in the dongle again after enable irq on the host. - * and rechedule dpc if interrupt is pended in the dongle. - * There is a chance to miss OOB interrupt while irq is disabled on the host. - * No need to do this with HW-OOB(level trigger) - */ - R_SDREG(newstatus, ®s->intstatus, retries); - if (bcmsdh_regfail(bus->sdh)) - newstatus = 0; - if (newstatus & bus->hostintmask) { - bus->ipend = TRUE; - resched = TRUE; - } -#endif /* defined(OOB_INTR_ONLY) && !defined(HW_OOB) */ - - if (TXCTLOK(bus) && bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL)) { - int ret, i; - uint8* frame_seq = bus->ctrl_frame_buf + SDPCM_FRAMETAG_LEN; - if (*frame_seq != bus->tx_seq) { - DHD_INFO(("%s IOCTL frame seq lag detected!" - " frm_seq:%d != bus->tx_seq:%d, corrected\n", - __FUNCTION__, *frame_seq, bus->tx_seq)); - *frame_seq = bus->tx_seq; - } - - ret = dhd_bcmsdh_send_buf(bus, bcmsdh_cur_sbwad(sdh), SDIO_FUNC_2, F2SYNC, - (uint8 *)bus->ctrl_frame_buf, (uint32)bus->ctrl_frame_len, - NULL, NULL, NULL); - ASSERT(ret != BCME_PENDING); - if (ret == BCME_NODEVICE) { - DHD_ERROR(("%s: Device asleep already\n", __FUNCTION__)); - } else if (ret < 0) { - /* On failure, abort the command and terminate the frame */ - DHD_INFO(("%s: sdio error %d, abort command and terminate frame.\n", - __FUNCTION__, ret)); - bus->tx_sderrs++; - - bcmsdh_abort(sdh, SDIO_FUNC_2); - - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_FRAMECTRL, - SFC_WF_TERM, NULL); - bus->f1regdata++; - - for (i = 0; i < 3; i++) { - uint8 hi, lo; - hi = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCHI, NULL); - lo = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCLO, NULL); - bus->f1regdata += 2; - if ((hi == 0) && (lo == 0)) - break; - } - } - if (ret == 0) { - bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP; - } - - bus->ctrl_frame_stat = FALSE; - dhd_wait_event_wakeup(bus->dhd); - } - /* Send queued frames (limit 1 if rx may still be pending) */ - else if ((bus->clkstate == CLK_AVAIL) && !bus->fcstate && - pktq_mlen(&bus->txq, ~bus->flowcontrol) && txlimit && DATAOK(bus)) { - framecnt = rxdone ? txlimit : MIN(txlimit, dhd_txminmax); - framecnt = dhdsdio_sendfromq(bus, framecnt); - txlimit -= framecnt; - } - /* Resched the DPC if ctrl cmd is pending on bus credit */ - if (bus->ctrl_frame_stat) - resched = TRUE; - - /* Resched if events or tx frames are pending, else await next interrupt */ - /* On failed register access, all bets are off: no resched or interrupts */ - if ((bus->dhd->busstate == DHD_BUS_DOWN) || bcmsdh_regfail(sdh)) { - if ((bus->sih->buscorerev >= 12) && !(dhdsdio_sleepcsr_get(bus) & - SBSDIO_FUNC1_SLEEPCSR_KSO_MASK)) { - /* Bus failed because of KSO */ - DHD_ERROR(("%s: Bus failed due to KSO\n", __FUNCTION__)); - bus->kso = FALSE; - } else { - DHD_ERROR(("%s: failed backplane access over SDIO, halting operation\n", - __FUNCTION__)); - bus->dhd->busstate = DHD_BUS_DOWN; - bus->intstatus = 0; - } - } else if (bus->clkstate == CLK_PENDING) { - /* Awaiting I_CHIPACTIVE; don't resched */ - } else if (bus->intstatus || bus->ipend || - (!bus->fcstate && pktq_mlen(&bus->txq, ~bus->flowcontrol) && DATAOK(bus)) || - PKT_AVAILABLE(bus, bus->intstatus)) { /* Read multiple frames */ - resched = TRUE; - } - - bus->dpc_sched = resched; - - /* If we're done for now, turn off clock request. */ - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && (bus->clkstate != CLK_PENDING)) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - } - -exit: - dhd_os_sdunlock(bus->dhd); - return resched; -} - -bool -dhd_bus_dpc(struct dhd_bus *bus) -{ - bool resched; - - /* Call the DPC directly. */ - DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); - resched = dhdsdio_dpc(bus); - - return resched; -} - -void -dhdsdio_isr(void *arg) -{ - dhd_bus_t *bus = (dhd_bus_t*)arg; - bcmsdh_info_t *sdh; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (!bus) { - DHD_ERROR(("%s : bus is null pointer , exit \n", __FUNCTION__)); - return; - } - sdh = bus->sdh; - - if (bus->dhd->busstate == DHD_BUS_DOWN) { - DHD_ERROR(("%s : bus is down. we have nothing to do\n", __FUNCTION__)); - return; - } - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - /* Count the interrupt call */ - bus->intrcount++; - bus->ipend = TRUE; - - /* Shouldn't get this interrupt if we're sleeping? */ - if (!SLPAUTO_ENAB(bus)) { - if (bus->sleeping) { - DHD_ERROR(("INTERRUPT WHILE SLEEPING??\n")); - return; - } else if (!KSO_ENAB(bus)) { - DHD_ERROR(("ISR in devsleep 1\n")); - } - } - - /* Disable additional interrupts (is this needed now)? */ - if (bus->intr) { - DHD_INTR(("%s: disable SDIO interrupts\n", __FUNCTION__)); - } else { - DHD_ERROR(("dhdsdio_isr() w/o interrupt configured!\n")); - } - - bcmsdh_intr_disable(sdh); - bus->intdis = TRUE; - -#if defined(SDIO_ISR_THREAD) - DHD_TRACE(("Calling dhdsdio_dpc() from %s\n", __FUNCTION__)); - DHD_OS_WAKE_LOCK(bus->dhd); - while (dhdsdio_dpc(bus)); - DHD_OS_WAKE_UNLOCK(bus->dhd); -#else - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); -#endif - -} - -#ifdef SDTEST -static void -dhdsdio_pktgen_init(dhd_bus_t *bus) -{ - /* Default to specified length, or full range */ - if (dhd_pktgen_len) { - bus->pktgen_maxlen = MIN(dhd_pktgen_len, MAX_PKTGEN_LEN); - bus->pktgen_minlen = bus->pktgen_maxlen; - } else { - bus->pktgen_maxlen = MAX_PKTGEN_LEN; - bus->pktgen_minlen = 0; - } - bus->pktgen_len = (uint16)bus->pktgen_minlen; - - /* Default to per-watchdog burst with 10s print time */ - bus->pktgen_freq = 1; - bus->pktgen_print = 10000 / dhd_watchdog_ms; - bus->pktgen_count = (dhd_pktgen * dhd_watchdog_ms + 999) / 1000; - - /* Default to echo mode */ - bus->pktgen_mode = DHD_PKTGEN_ECHO; - bus->pktgen_stop = 1; -} - -static void -dhdsdio_pktgen(dhd_bus_t *bus) -{ - void *pkt; - uint8 *data; - uint pktcount; - uint fillbyte; - osl_t *osh = bus->dhd->osh; - uint16 len; - - /* Display current count if appropriate */ - if (bus->pktgen_print && (++bus->pktgen_ptick >= bus->pktgen_print)) { - bus->pktgen_ptick = 0; - printf("%s: send attempts %d rcvd %d\n", - __FUNCTION__, bus->pktgen_sent, bus->pktgen_rcvd); - } - - /* For recv mode, just make sure dongle has started sending */ - if (bus->pktgen_mode == DHD_PKTGEN_RECV) { - if (bus->pktgen_rcv_state == PKTGEN_RCV_IDLE) { - bus->pktgen_rcv_state = PKTGEN_RCV_ONGOING; - dhdsdio_sdtest_set(bus, (uint8)bus->pktgen_total); - } - return; - } - - /* Otherwise, generate or request the specified number of packets */ - for (pktcount = 0; pktcount < bus->pktgen_count; pktcount++) { - /* Stop if total has been reached */ - if (bus->pktgen_total && (bus->pktgen_sent >= bus->pktgen_total)) { - bus->pktgen_count = 0; - break; - } - - /* Allocate an appropriate-sized packet */ - len = bus->pktgen_len; - if (!(pkt = PKTGET(osh, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN), - TRUE))) {; - DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); - break; - } - PKTALIGN(osh, pkt, (len + SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); - data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; - - /* Write test header cmd and extra based on mode */ - switch (bus->pktgen_mode) { - case DHD_PKTGEN_ECHO: - *data++ = SDPCM_TEST_ECHOREQ; - *data++ = (uint8)bus->pktgen_sent; - break; - - case DHD_PKTGEN_SEND: - *data++ = SDPCM_TEST_DISCARD; - *data++ = (uint8)bus->pktgen_sent; - break; - - case DHD_PKTGEN_RXBURST: - *data++ = SDPCM_TEST_BURST; - *data++ = (uint8)bus->pktgen_count; - break; - - default: - DHD_ERROR(("Unrecognized pktgen mode %d\n", bus->pktgen_mode)); - PKTFREE(osh, pkt, TRUE); - bus->pktgen_count = 0; - return; - } - - /* Write test header length field */ - *data++ = (len >> 0); - *data++ = (len >> 8); - - /* Then fill in the remainder -- N/A for burst, but who cares... */ - for (fillbyte = 0; fillbyte < len; fillbyte++) - *data++ = SDPCM_TEST_FILL(fillbyte, (uint8)bus->pktgen_sent); - -#ifdef DHD_DEBUG - if (DHD_BYTES_ON() && DHD_DATA_ON()) { - data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; - prhex("dhdsdio_pktgen: Tx Data", data, PKTLEN(osh, pkt) - SDPCM_HDRLEN); - } -#endif - - /* Send it */ - if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE)) { - bus->pktgen_fail++; - if (bus->pktgen_stop && bus->pktgen_stop == bus->pktgen_fail) - bus->pktgen_count = 0; - } - bus->pktgen_sent++; - - /* Bump length if not fixed, wrap at max */ - if (++bus->pktgen_len > bus->pktgen_maxlen) - bus->pktgen_len = (uint16)bus->pktgen_minlen; - - /* Special case for burst mode: just send one request! */ - if (bus->pktgen_mode == DHD_PKTGEN_RXBURST) - break; - } -} - -static void -dhdsdio_sdtest_set(dhd_bus_t *bus, uint8 count) -{ - void *pkt; - uint8 *data; - osl_t *osh = bus->dhd->osh; - - /* Allocate the packet */ - if (!(pkt = PKTGET(osh, SDPCM_HDRLEN + SDPCM_TEST_HDRLEN + DHD_SDALIGN, TRUE))) { - DHD_ERROR(("%s: PKTGET failed!\n", __FUNCTION__)); - return; - } - PKTALIGN(osh, pkt, (SDPCM_HDRLEN + SDPCM_TEST_HDRLEN), DHD_SDALIGN); - data = (uint8*)PKTDATA(osh, pkt) + SDPCM_HDRLEN; - - /* Fill in the test header */ - *data++ = SDPCM_TEST_SEND; - *data++ = count; - *data++ = (bus->pktgen_maxlen >> 0); - *data++ = (bus->pktgen_maxlen >> 8); - - /* Send it */ - if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE)) - bus->pktgen_fail++; -} - - -static void -dhdsdio_testrcv(dhd_bus_t *bus, void *pkt, uint seq) -{ - osl_t *osh = bus->dhd->osh; - uint8 *data; - uint pktlen; - - uint8 cmd; - uint8 extra; - uint16 len; - uint16 offset; - - /* Check for min length */ - if ((pktlen = PKTLEN(osh, pkt)) < SDPCM_TEST_HDRLEN) { - DHD_ERROR(("dhdsdio_restrcv: toss runt frame, pktlen %d\n", pktlen)); - PKTFREE(osh, pkt, FALSE); - return; - } - - /* Extract header fields */ - data = PKTDATA(osh, pkt); - cmd = *data++; - extra = *data++; - len = *data++; len += *data++ << 8; - DHD_TRACE(("%s:cmd:%d, xtra:%d,len:%d\n", __FUNCTION__, cmd, extra, len)); - /* Check length for relevant commands */ - if (cmd == SDPCM_TEST_DISCARD || cmd == SDPCM_TEST_ECHOREQ || cmd == SDPCM_TEST_ECHORSP) { - if (pktlen != len + SDPCM_TEST_HDRLEN) { - DHD_ERROR(("dhdsdio_testrcv: frame length mismatch, pktlen %d seq %d" - " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); - PKTFREE(osh, pkt, FALSE); - return; - } - } - - /* Process as per command */ - switch (cmd) { - case SDPCM_TEST_ECHOREQ: - /* Rx->Tx turnaround ok (even on NDIS w/current implementation) */ - *(uint8 *)(PKTDATA(osh, pkt)) = SDPCM_TEST_ECHORSP; - if (dhdsdio_txpkt(bus, pkt, SDPCM_TEST_CHANNEL, TRUE) == 0) { - bus->pktgen_sent++; - } else { - bus->pktgen_fail++; - PKTFREE(osh, pkt, FALSE); - } - bus->pktgen_rcvd++; - break; - - case SDPCM_TEST_ECHORSP: - if (bus->ext_loop) { - PKTFREE(osh, pkt, FALSE); - bus->pktgen_rcvd++; - break; - } - - for (offset = 0; offset < len; offset++, data++) { - if (*data != SDPCM_TEST_FILL(offset, extra)) { - DHD_ERROR(("dhdsdio_testrcv: echo data mismatch: " - "offset %d (len %d) expect 0x%02x rcvd 0x%02x\n", - offset, len, SDPCM_TEST_FILL(offset, extra), *data)); - break; - } - } - PKTFREE(osh, pkt, FALSE); - bus->pktgen_rcvd++; - break; - - case SDPCM_TEST_DISCARD: - { - int i = 0; - uint8 *prn = data; - uint8 testval = extra; - for (i = 0; i < len; i++) { - if (*prn != testval) { - DHD_ERROR(("DIErr@Pkt#:%d,Ix:%d, expected:0x%x, got:0x%x\n", - i, bus->pktgen_rcvd_rcvsession, testval, *prn)); - prn++; testval++; - } - } - } - PKTFREE(osh, pkt, FALSE); - bus->pktgen_rcvd++; - break; - - case SDPCM_TEST_BURST: - case SDPCM_TEST_SEND: - default: - DHD_INFO(("dhdsdio_testrcv: unsupported or unknown command, pktlen %d seq %d" - " cmd %d extra %d len %d\n", pktlen, seq, cmd, extra, len)); - PKTFREE(osh, pkt, FALSE); - break; - } - - /* For recv mode, stop at limit (and tell dongle to stop sending) */ - if (bus->pktgen_mode == DHD_PKTGEN_RECV) { - if (bus->pktgen_rcv_state != PKTGEN_RCV_IDLE) { - bus->pktgen_rcvd_rcvsession++; - - if (bus->pktgen_total && - (bus->pktgen_rcvd_rcvsession >= bus->pktgen_total)) { - bus->pktgen_count = 0; - DHD_ERROR(("Pktgen:rcv test complete!\n")); - bus->pktgen_rcv_state = PKTGEN_RCV_IDLE; - dhdsdio_sdtest_set(bus, FALSE); - bus->pktgen_rcvd_rcvsession = 0; - } - } - } -} -#endif /* SDTEST */ - -extern void -dhd_disable_intr(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus; - bus = dhdp->bus; - bcmsdh_intr_disable(bus->sdh); -} - - -extern bool -dhd_bus_watchdog(dhd_pub_t *dhdp) -{ - dhd_bus_t *bus; - - DHD_TIMER(("%s: Enter\n", __FUNCTION__)); - - bus = dhdp->bus; - - if (bus->dhd->dongle_reset) - return FALSE; - - /* Ignore the timer if simulating bus down */ - if (!SLPAUTO_ENAB(bus) && bus->sleeping) - return FALSE; - - if (dhdp->busstate == DHD_BUS_DOWN) - return FALSE; - - /* Poll period: check device if appropriate. */ - if (!SLPAUTO_ENAB(bus) && (bus->poll && (++bus->polltick >= bus->pollrate))) { - uint32 intstatus = 0; - - /* Reset poll tick */ - bus->polltick = 0; - - /* Check device if no interrupts */ - if (!bus->intr || (bus->intrcount == bus->lastintrs)) { - - if (!bus->dpc_sched) { - uint8 devpend; - devpend = bcmsdh_cfg_read(bus->sdh, SDIO_FUNC_0, - SDIOD_CCCR_INTPEND, NULL); - intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2); - } - - /* If there is something, make like the ISR and schedule the DPC */ - if (intstatus) { - bus->pollcnt++; - bus->ipend = TRUE; - if (bus->intr) { - bcmsdh_intr_disable(bus->sdh); - } - bus->dpc_sched = TRUE; - dhd_sched_dpc(bus->dhd); - - } - } - - /* Update interrupt tracking */ - bus->lastintrs = bus->intrcount; - } - -#ifdef DHD_DEBUG - /* Poll for console output periodically */ - if (dhdp->busstate == DHD_BUS_DATA && dhd_console_ms != 0) { - bus->console.count += dhd_watchdog_ms; - if (bus->console.count >= dhd_console_ms) { - bus->console.count -= dhd_console_ms; - /* Make sure backplane clock is on */ - if (SLPAUTO_ENAB(bus)) - dhdsdio_bussleep(bus, FALSE); - else - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - if (dhdsdio_readconsole(bus) < 0) - dhd_console_ms = 0; /* On error, stop trying */ - } - } -#endif /* DHD_DEBUG */ - -#ifdef SDTEST - /* Generate packets if configured */ - if (bus->pktgen_count && (++bus->pktgen_tick >= bus->pktgen_freq)) { - /* Make sure backplane clock is on */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - bus->pktgen_tick = 0; - dhdsdio_pktgen(bus); - } -#endif - - /* On idle timeout clear activity flag and/or turn off clock */ -#ifdef DHD_USE_IDLECOUNT - - if (bus->activity) - bus->activity = FALSE; - else { - bus->idlecount++; - - if (bus->idlecount >= bus->idletime) { - DHD_TIMER(("%s: DHD Idle state!!\n", __FUNCTION__)); - - if (SLPAUTO_ENAB(bus)) { - if (dhdsdio_bussleep(bus, TRUE) != BCME_BUSY) - dhd_os_wd_timer(bus->dhd, 0); - } else - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - - bus->idlecount = 0; - } - } -#else - if ((bus->idletime > 0) && (bus->clkstate == CLK_AVAIL)) { - if (++bus->idlecount >= bus->idletime) { - bus->idlecount = 0; - if (bus->activity) { - bus->activity = FALSE; - if (SLPAUTO_ENAB(bus)) - dhdsdio_bussleep(bus, TRUE); - else - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - } - } - } -#endif /* DHD_USE_IDLECOUNT */ - - return bus->ipend; -} - -#ifdef DHD_DEBUG -extern int -dhd_bus_console_in(dhd_pub_t *dhdp, uchar *msg, uint msglen) -{ - dhd_bus_t *bus = dhdp->bus; - uint32 addr, val; - int rv; - void *pkt; - - /* Address could be zero if CONSOLE := 0 in dongle Makefile */ - if (bus->console_addr == 0) - return BCME_UNSUPPORTED; - - /* Exclusive bus access */ - dhd_os_sdlock(bus->dhd); - - /* Don't allow input if dongle is in reset */ - if (bus->dhd->dongle_reset) { - dhd_os_sdunlock(bus->dhd); - return BCME_NOTREADY; - } - - /* Request clock to allow SDIO accesses */ - BUS_WAKE(bus); - /* No pend allowed since txpkt is called later, ht clk has to be on */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - /* Zero cbuf_index */ - addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf_idx); - val = htol32(0); - if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) - goto done; - - /* Write message into cbuf */ - addr = bus->console_addr + OFFSETOF(hndrte_cons_t, cbuf); - if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)msg, msglen)) < 0) - goto done; - - /* Write length into vcons_in */ - addr = bus->console_addr + OFFSETOF(hndrte_cons_t, vcons_in); - val = htol32(msglen); - if ((rv = dhdsdio_membytes(bus, TRUE, addr, (uint8 *)&val, sizeof(val))) < 0) - goto done; - - /* Bump dongle by sending an empty packet on the event channel. - * sdpcm_sendup (RX) checks for virtual console input. - */ - if ((pkt = PKTGET(bus->dhd->osh, 4 + SDPCM_RESERVE, TRUE)) != NULL) - dhdsdio_txpkt(bus, pkt, SDPCM_EVENT_CHANNEL, TRUE); - -done: - if ((bus->idletime == DHD_IDLE_IMMEDIATE) && !bus->dpc_sched) { - bus->activity = FALSE; - dhdsdio_clkctl(bus, CLK_NONE, TRUE); - } - - dhd_os_sdunlock(bus->dhd); - - return rv; -} -#endif /* DHD_DEBUG */ - -#ifdef DHD_DEBUG -static void -dhd_dump_cis(uint fn, uint8 *cis) -{ - uint byte, tag, tdata; - DHD_INFO(("Function %d CIS:\n", fn)); - - for (tdata = byte = 0; byte < SBSDIO_CIS_SIZE_LIMIT; byte++) { - if ((byte % 16) == 0) - DHD_INFO((" ")); - DHD_INFO(("%02x ", cis[byte])); - if ((byte % 16) == 15) - DHD_INFO(("\n")); - if (!tdata--) { - tag = cis[byte]; - if (tag == 0xff) - break; - else if (!tag) - tdata = 0; - else if ((byte + 1) < SBSDIO_CIS_SIZE_LIMIT) - tdata = cis[byte + 1] + 1; - else - DHD_INFO(("]")); - } - } - if ((byte % 16) != 15) - DHD_INFO(("\n")); -} -#endif /* DHD_DEBUG */ - -static bool -dhdsdio_chipmatch(uint16 chipid) -{ - if (chipid == BCM4325_CHIP_ID) - return TRUE; - if (chipid == BCM4329_CHIP_ID) - return TRUE; - if (chipid == BCM4315_CHIP_ID) - return TRUE; - if (chipid == BCM4319_CHIP_ID) - return TRUE; - if (chipid == BCM4336_CHIP_ID) - return TRUE; - if (chipid == BCM4330_CHIP_ID) - return TRUE; - if (chipid == BCM43237_CHIP_ID) - return TRUE; - if (chipid == BCM43362_CHIP_ID) - return TRUE; - if (chipid == BCM4314_CHIP_ID) - return TRUE; - if (chipid == BCM4334_CHIP_ID) - return TRUE; - if (chipid == BCM43239_CHIP_ID) - return TRUE; - if (chipid == BCM4324_CHIP_ID) - return TRUE; - return FALSE; -} - -static void * -dhdsdio_probe(uint16 venid, uint16 devid, uint16 bus_no, uint16 slot, - uint16 func, uint bustype, void *regsva, osl_t * osh, void *sdh) -{ - int ret; - dhd_bus_t *bus; -#ifdef GET_CUSTOM_MAC_ENABLE - struct ether_addr ea_addr; -#endif /* GET_CUSTOM_MAC_ENABLE */ - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - - if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { - DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); - } - else { - DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); - } - mutex_lock(&_dhd_sdio_mutex_lock_); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ - - /* Init global variables at run-time, not as part of the declaration. - * This is required to support init/de-init of the driver. Initialization - * of globals as part of the declaration results in non-deterministic - * behavior since the value of the globals may be different on the - * first time that the driver is initialized vs subsequent initializations. - */ - dhd_txbound = DHD_TXBOUND; - dhd_rxbound = DHD_RXBOUND; - dhd_alignctl = TRUE; - sd1idle = TRUE; - dhd_readahead = TRUE; - retrydata = FALSE; - dhd_doflow = FALSE; - dhd_dongle_memsize = 0; - dhd_txminmax = DHD_TXMINMAX; - - forcealign = TRUE; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - DHD_INFO(("%s: venid 0x%04x devid 0x%04x\n", __FUNCTION__, venid, devid)); - - /* We make assumptions about address window mappings */ - ASSERT((uintptr)regsva == SI_ENUM_BASE); - - /* BCMSDH passes venid and devid based on CIS parsing -- but low-power start - * means early parse could fail, so here we should get either an ID - * we recognize OR (-1) indicating we must request power first. - */ - /* Check the Vendor ID */ - switch (venid) { - case 0x0000: - case VENDOR_BROADCOM: - break; - default: - DHD_ERROR(("%s: unknown vendor: 0x%04x\n", - __FUNCTION__, venid)); - goto forcereturn; - } - - /* Check the Device ID and make sure it's one that we support */ - switch (devid) { - case BCM4325_D11DUAL_ID: /* 4325 802.11a/g id */ - case BCM4325_D11G_ID: /* 4325 802.11g 2.4Ghz band id */ - case BCM4325_D11A_ID: /* 4325 802.11a 5Ghz band id */ - DHD_INFO(("%s: found 4325 Dongle\n", __FUNCTION__)); - break; - case BCM4329_D11N_ID: /* 4329 802.11n dualband device */ - case BCM4329_D11N2G_ID: /* 4329 802.11n 2.4G device */ - case BCM4329_D11N5G_ID: /* 4329 802.11n 5G device */ - case 0x4329: - DHD_INFO(("%s: found 4329 Dongle\n", __FUNCTION__)); - break; - case BCM4315_D11DUAL_ID: /* 4315 802.11a/g id */ - case BCM4315_D11G_ID: /* 4315 802.11g id */ - case BCM4315_D11A_ID: /* 4315 802.11a id */ - DHD_INFO(("%s: found 4315 Dongle\n", __FUNCTION__)); - break; - case BCM4319_D11N_ID: /* 4319 802.11n id */ - case BCM4319_D11N2G_ID: /* 4319 802.11n2g id */ - case BCM4319_D11N5G_ID: /* 4319 802.11n5g id */ - DHD_INFO(("%s: found 4319 Dongle\n", __FUNCTION__)); - break; - case 0: - DHD_INFO(("%s: allow device id 0, will check chip internals\n", - __FUNCTION__)); - break; - - default: - DHD_ERROR(("%s: skipping 0x%04x/0x%04x, not a dongle\n", - __FUNCTION__, venid, devid)); - goto forcereturn; - } - - if (osh == NULL) { - /* Ask the OS interface part for an OSL handle */ - if (!(osh = dhd_osl_attach(sdh, DHD_BUS))) { - DHD_ERROR(("%s: osl_attach failed!\n", __FUNCTION__)); - goto forcereturn; - } - } - - /* Allocate private bus interface state */ - if (!(bus = MALLOC(osh, sizeof(dhd_bus_t)))) { - DHD_ERROR(("%s: MALLOC of dhd_bus_t failed\n", __FUNCTION__)); - goto fail; - } - bzero(bus, sizeof(dhd_bus_t)); - bus->sdh = sdh; - bus->cl_devid = (uint16)devid; - bus->bus = DHD_BUS; - bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1; - bus->usebufpool = FALSE; /* Use bufpool if allocated, else use locally malloced rxbuf */ - - /* attach the common module */ - dhd_common_init(osh); - - /* attempt to attach to the dongle */ - if (!(dhdsdio_probe_attach(bus, osh, sdh, regsva, devid))) { - DHD_ERROR(("%s: dhdsdio_probe_attach failed\n", __FUNCTION__)); - goto fail; - } - - /* Attach to the dhd/OS/network interface */ - if (!(bus->dhd = dhd_attach(osh, bus, SDPCM_RESERVE))) { - DHD_ERROR(("%s: dhd_attach failed\n", __FUNCTION__)); - goto fail; - } - - - /* Allocate buffers */ - if (!(dhdsdio_probe_malloc(bus, osh, sdh))) { - DHD_ERROR(("%s: dhdsdio_probe_malloc failed\n", __FUNCTION__)); - goto fail; - } - - if (!(dhdsdio_probe_init(bus, osh, sdh))) { - DHD_ERROR(("%s: dhdsdio_probe_init failed\n", __FUNCTION__)); - goto fail; - } - - if (bus->intr) { - /* Register interrupt callback, but mask it (not operational yet). */ - DHD_INTR(("%s: disable SDIO interrupts (not interested yet)\n", __FUNCTION__)); - bcmsdh_intr_disable(sdh); - if ((ret = bcmsdh_intr_reg(sdh, dhdsdio_isr, bus)) != 0) { - DHD_ERROR(("%s: FAILED: bcmsdh_intr_reg returned %d\n", - __FUNCTION__, ret)); - goto fail; - } - DHD_INTR(("%s: registered SDIO interrupt function ok\n", __FUNCTION__)); - } else { - DHD_INFO(("%s: SDIO interrupt function is NOT registered due to polling mode\n", - __FUNCTION__)); - } - - DHD_INFO(("%s: completed!!\n", __FUNCTION__)); - -#ifdef GET_CUSTOM_MAC_ENABLE - /* Read MAC address from external customer place */ - memset(&ea_addr, 0, sizeof(ea_addr)); - ret = dhd_custom_get_mac_address(ea_addr.octet); - if (!ret) { - memcpy(bus->dhd->mac.octet, (void *)&ea_addr, ETHER_ADDR_LEN); - } -#endif /* GET_CUSTOM_MAC_ENABLE */ - - /* if firmware path present try to download and bring up bus */ - if (dhd_download_fw_on_driverload && (ret = dhd_bus_start(bus->dhd)) != 0) { - DHD_ERROR(("%s: dhd_bus_start failed\n", __FUNCTION__)); - if (ret == BCME_NOTUP) - goto fail; - } - /* Ok, have the per-port tell the stack we're open for business */ - if (dhd_net_attach(bus->dhd, 0) != 0) { - DHD_ERROR(("%s: Net attach failed!!\n", __FUNCTION__)); - goto fail; - } - -#ifdef BCMHOST_XTAL_PU_TIME_MOD -#ifdef BCM4334_CHIP - bcmsdh_reg_write(bus->sdh, 0x18000620, 2, 11); - bcmsdh_reg_write(bus->sdh, 0x18000628, 4, 0x00F80001); -#endif -#endif -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&_dhd_sdio_mutex_lock_); - DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ - - return bus; - -fail: - dhdsdio_release(bus, osh); - -forcereturn: -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&_dhd_sdio_mutex_lock_); - DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27)) */ - - return NULL; -} - -static bool -dhdsdio_probe_attach(struct dhd_bus *bus, osl_t *osh, void *sdh, void *regsva, - uint16 devid) -{ - int err = 0; - uint8 clkctl = 0; - -#ifdef BCM4334_CHECK_CHIP_REV - uint8 data[4]; - uint32 unique_id; -#endif - - bus->alp_only = TRUE; - bus->sih = NULL; - - /* Return the window to backplane enumeration space for core access */ - if (dhdsdio_set_siaddr_window(bus, SI_ENUM_BASE)) { - DHD_ERROR(("%s: FAILED to return to SI_ENUM_BASE\n", __FUNCTION__)); - } - -#ifdef DHD_DEBUG - DHD_ERROR(("F1 signature read @0x18000000=0x%4x\n", - bcmsdh_reg_read(bus->sdh, SI_ENUM_BASE, 4))); - -#endif /* DHD_DEBUG */ - - - /* Force PLL off until si_attach() programs PLL control regs */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, DHD_INIT_CLKCTL1, &err); - if (!err) - clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, &err); - - if (err || ((clkctl & ~SBSDIO_AVBITS) != DHD_INIT_CLKCTL1)) { - DHD_ERROR(("dhdsdio_probe: ChipClkCSR access: err %d wrote 0x%02x read 0x%02x\n", - err, DHD_INIT_CLKCTL1, clkctl)); - goto fail; - } - -#ifdef DHD_DEBUG - if (DHD_INFO_ON()) { - uint fn, numfn; - uint8 *cis[SDIOD_MAX_IOFUNCS]; - int err = 0; - - numfn = bcmsdh_query_iofnum(sdh); - ASSERT(numfn <= SDIOD_MAX_IOFUNCS); - - /* Make sure ALP is available before trying to read CIS */ - SPINWAIT(((clkctl = bcmsdh_cfg_read(sdh, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, NULL)), - !SBSDIO_ALPAV(clkctl)), PMU_MAX_TRANSITION_DLY); - - /* Now request ALP be put on the bus */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, - DHD_INIT_CLKCTL2, &err); - OSL_DELAY(65); - - for (fn = 0; fn <= numfn; fn++) { - if (!(cis[fn] = MALLOC(osh, SBSDIO_CIS_SIZE_LIMIT))) { - DHD_INFO(("dhdsdio_probe: fn %d cis malloc failed\n", fn)); - break; - } - bzero(cis[fn], SBSDIO_CIS_SIZE_LIMIT); - - if ((err = bcmsdh_cis_read(sdh, fn, cis[fn], SBSDIO_CIS_SIZE_LIMIT))) { - DHD_INFO(("dhdsdio_probe: fn %d cis read err %d\n", fn, err)); - MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); - break; - } - dhd_dump_cis(fn, cis[fn]); - } - - while (fn-- > 0) { - ASSERT(cis[fn]); - MFREE(osh, cis[fn], SBSDIO_CIS_SIZE_LIMIT); - } - - if (err) { - DHD_ERROR(("dhdsdio_probe: failure reading or parsing CIS\n")); - goto fail; - } - } -#endif /* DHD_DEBUG */ - - /* si_attach() will provide an SI handle and scan the backplane */ - if (!(bus->sih = si_attach((uint)devid, osh, regsva, DHD_BUS, sdh, - &bus->vars, &bus->varsz))) { - DHD_ERROR(("%s: si_attach failed!\n", __FUNCTION__)); - goto fail; - } - - bcmsdh_chipinfo(sdh, bus->sih->chip, bus->sih->chiprev); - -#ifdef BCM4334_CHECK_CHIP_REV - if (bus->sih->chip == BCM4334_CHIP_ID) { - g_chipver = bus->sih->chiprev; - if (g_chipver == 0x2) { - dhdsdio_membytes(bus, FALSE, REV_ID_ADDR, data, 4); - unique_id = load32_ua(data); - if (unique_id == 0x30312E36) - g_chipver = 0x1; - } - } else { - g_chipver = 0; - } -#endif - - if (!dhdsdio_chipmatch((uint16)bus->sih->chip)) { - DHD_ERROR(("%s: unsupported chip: 0x%04x\n", - __FUNCTION__, bus->sih->chip)); - goto fail; - } - - if (bus->sih->buscorerev >= 12) - dhdsdio_clk_kso_init(bus); - else - bus->kso = TRUE; - - if (CST4330_CHIPMODE_SDIOD(bus->sih->chipst)) { - } - - si_sdiod_drive_strength_init(bus->sih, osh, dhd_sdiod_drive_strength); - - - /* Get info on the ARM and SOCRAM cores... */ - if (!DHD_NOPMU(bus)) { - if ((si_setcore(bus->sih, ARM7S_CORE_ID, 0)) || - (si_setcore(bus->sih, ARMCM3_CORE_ID, 0))) { - bus->armrev = si_corerev(bus->sih); - } else { - DHD_ERROR(("%s: failed to find ARM core!\n", __FUNCTION__)); - goto fail; - } - if (!(bus->orig_ramsize = si_socram_size(bus->sih))) { - DHD_ERROR(("%s: failed to find SOCRAM memory!\n", __FUNCTION__)); - goto fail; - } - - bus->ramsize = bus->orig_ramsize; - if (dhd_dongle_memsize) - dhd_dongle_setmemsize(bus, dhd_dongle_memsize); - - DHD_ERROR(("DHD: dongle ram size is set to %d(orig %d)\n", - bus->ramsize, bus->orig_ramsize)); - - bus->srmemsize = si_socram_srmem_size(bus->sih); - } - - /* ...but normally deal with the SDPCMDEV core */ - if (!(bus->regs = si_setcore(bus->sih, PCMCIA_CORE_ID, 0)) && - !(bus->regs = si_setcore(bus->sih, SDIOD_CORE_ID, 0))) { - DHD_ERROR(("%s: failed to find SDIODEV core!\n", __FUNCTION__)); - goto fail; - } - bus->sdpcmrev = si_corerev(bus->sih); - - /* Set core control so an SDIO reset does a backplane reset */ - OR_REG(osh, &bus->regs->corecontrol, CC_BPRESEN); - bus->rxint_mode = SDIO_DEVICE_HMB_RXINT; - - if ((bus->sih->buscoretype == SDIOD_CORE_ID) && (bus->sdpcmrev >= 4) && - (bus->rxint_mode == SDIO_DEVICE_RXDATAINT_MODE_1)) - { - uint32 val; - - val = R_REG(osh, &bus->regs->corecontrol); - val &= ~CC_XMTDATAAVAIL_MODE; - val |= CC_XMTDATAAVAIL_CTRL; - W_REG(osh, &bus->regs->corecontrol, val); - } - - - pktq_init(&bus->txq, (PRIOMASK + 1), QLEN); - - /* Locate an appropriately-aligned portion of hdrbuf */ - bus->rxhdr = (uint8 *)ROUNDUP((uintptr)&bus->hdrbuf[0], DHD_SDALIGN); - - /* Set the poll and/or interrupt flags */ - bus->intr = (bool)dhd_intr; - if ((bus->poll = (bool)dhd_poll)) - bus->pollrate = 1; - - return TRUE; - -fail: - if (bus->sih != NULL) - si_detach(bus->sih); - return FALSE; -} - -static bool -dhdsdio_probe_malloc(dhd_bus_t *bus, osl_t *osh, void *sdh) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd->maxctl) { - bus->rxblen = ROUNDUP((bus->dhd->maxctl + SDPCM_HDRLEN), ALIGNMENT) + DHD_SDALIGN; - if (!(bus->rxbuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_RXBUF, bus->rxblen))) { - DHD_ERROR(("%s: MALLOC of %d-byte rxbuf failed\n", - __FUNCTION__, bus->rxblen)); - goto fail; - } - } - /* Allocate buffer to receive glomed packet */ - if (!(bus->databuf = DHD_OS_PREALLOC(osh, DHD_PREALLOC_DATABUF, MAX_DATA_BUF))) { - DHD_ERROR(("%s: MALLOC of %d-byte databuf failed\n", - __FUNCTION__, MAX_DATA_BUF)); - /* release rxbuf which was already located as above */ - if (!bus->rxblen) - DHD_OS_PREFREE(osh, bus->rxbuf, bus->rxblen); - goto fail; - } - - /* Align the buffer */ - if ((uintptr)bus->databuf % DHD_SDALIGN) - bus->dataptr = bus->databuf + (DHD_SDALIGN - ((uintptr)bus->databuf % DHD_SDALIGN)); - else - bus->dataptr = bus->databuf; - - return TRUE; - -fail: - return FALSE; -} - -static bool -dhdsdio_probe_init(dhd_bus_t *bus, osl_t *osh, void *sdh) -{ - int32 fnum; - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - -#ifdef SDTEST - dhdsdio_pktgen_init(bus); -#endif /* SDTEST */ - - /* Disable F2 to clear any intermediate frame state on the dongle */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_0, SDIOD_CCCR_IOEN, SDIO_FUNC_ENABLE_1, NULL); - - bus->dhd->busstate = DHD_BUS_DOWN; - bus->sleeping = FALSE; - bus->rxflow = FALSE; - bus->prev_rxlim_hit = 0; - - /* Done with backplane-dependent accesses, can drop clock... */ - bcmsdh_cfg_write(sdh, SDIO_FUNC_1, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); - - /* ...and initialize clock/power states */ - bus->clkstate = CLK_SDONLY; - bus->idletime = (int32)dhd_idletime; - bus->idleclock = DHD_IDLE_ACTIVE; - - /* Query the SD clock speed */ - if (bcmsdh_iovar_op(sdh, "sd_divisor", NULL, 0, - &bus->sd_divisor, sizeof(int32), FALSE) != BCME_OK) { - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_divisor")); - bus->sd_divisor = -1; - } else { - DHD_INFO(("%s: Initial value for %s is %d\n", - __FUNCTION__, "sd_divisor", bus->sd_divisor)); - } - - /* Query the SD bus mode */ - if (bcmsdh_iovar_op(sdh, "sd_mode", NULL, 0, - &bus->sd_mode, sizeof(int32), FALSE) != BCME_OK) { - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_mode")); - bus->sd_mode = -1; - } else { - DHD_INFO(("%s: Initial value for %s is %d\n", - __FUNCTION__, "sd_mode", bus->sd_mode)); - } - - /* Query the F2 block size, set roundup accordingly */ - fnum = 2; - if (bcmsdh_iovar_op(sdh, "sd_blocksize", &fnum, sizeof(int32), - &bus->blocksize, sizeof(int32), FALSE) != BCME_OK) { - bus->blocksize = 0; - DHD_ERROR(("%s: fail on %s get\n", __FUNCTION__, "sd_blocksize")); - } else { - DHD_INFO(("%s: Initial value for %s is %d\n", - __FUNCTION__, "sd_blocksize", bus->blocksize)); - } - bus->roundup = MIN(max_roundup, bus->blocksize); - - /* Query if bus module supports packet chaining, default to use if supported */ - if (bcmsdh_iovar_op(sdh, "sd_rxchain", NULL, 0, - &bus->sd_rxchain, sizeof(int32), FALSE) != BCME_OK) { - bus->sd_rxchain = FALSE; - } else { - DHD_INFO(("%s: bus module (through bcmsdh API) %s chaining\n", - __FUNCTION__, (bus->sd_rxchain ? "supports" : "does not support"))); - } - bus->use_rxchain = (bool)bus->sd_rxchain; - - return TRUE; -} - -bool -dhd_bus_download_firmware(struct dhd_bus *bus, osl_t *osh, - char *pfw_path, char *pnv_path) -{ - bool ret; - bus->fw_path = pfw_path; - bus->nv_path = pnv_path; - - ret = dhdsdio_download_firmware(bus, osh, bus->sdh); - - - return ret; -} - -static bool -dhdsdio_download_firmware(struct dhd_bus *bus, osl_t *osh, void *sdh) -{ - bool ret; - - DHD_OS_WAKE_LOCK(bus->dhd); - - /* Download the firmware */ - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - - ret = _dhdsdio_download_firmware(bus) == 0; - - dhdsdio_clkctl(bus, CLK_SDONLY, FALSE); - - DHD_OS_WAKE_UNLOCK(bus->dhd); - return ret; -} - -/* Detach and free everything */ -static void -dhdsdio_release(dhd_bus_t *bus, osl_t *osh) -{ - bool dongle_isolation = FALSE; - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus) { - ASSERT(osh); - - if (bus->dhd) { - dongle_isolation = bus->dhd->dongle_isolation; - dhd_detach(bus->dhd); - } - - /* De-register interrupt handler */ - bcmsdh_intr_disable(bus->sdh); - bcmsdh_intr_dereg(bus->sdh); - - if (bus->dhd) { - dhdsdio_release_dongle(bus, osh, dongle_isolation, TRUE); - dhd_free(bus->dhd); - bus->dhd = NULL; - } - - dhdsdio_release_malloc(bus, osh); - -#ifdef DHD_DEBUG - if (bus->console.buf != NULL) - MFREE(osh, bus->console.buf, bus->console.bufsize); -#endif - - MFREE(osh, bus, sizeof(dhd_bus_t)); - } - - if (osh) - dhd_osl_detach(osh); - - DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); -} - -static void -dhdsdio_release_malloc(dhd_bus_t *bus, osl_t *osh) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus->dhd && bus->dhd->dongle_reset) - return; - - if (bus->rxbuf) { -#ifndef CONFIG_DHD_USE_STATIC_BUF - MFREE(osh, bus->rxbuf, bus->rxblen); -#endif - bus->rxctl = bus->rxbuf = NULL; - bus->rxlen = 0; - } - - if (bus->databuf) { -#ifndef CONFIG_DHD_USE_STATIC_BUF - MFREE(osh, bus->databuf, MAX_DATA_BUF); -#endif - bus->databuf = NULL; - } - - if (bus->vars && bus->varsz) { - MFREE(osh, bus->vars, bus->varsz); - bus->vars = NULL; - } - -} - - -static void -dhdsdio_release_dongle(dhd_bus_t *bus, osl_t *osh, bool dongle_isolation, bool reset_flag) -{ - DHD_TRACE(("%s: Enter bus->dhd %p bus->dhd->dongle_reset %d \n", __FUNCTION__, - bus->dhd, bus->dhd->dongle_reset)); - - if ((bus->dhd && bus->dhd->dongle_reset) && reset_flag) - return; - - if (bus->sih) { - if (bus->dhd) { - dhdsdio_clkctl(bus, CLK_AVAIL, FALSE); - } -#if !defined(BCMLXSDMMC) - if (KSO_ENAB(bus) && (dongle_isolation == FALSE)) - si_watchdog(bus->sih, 4); -#endif /* !defined(BCMLXSDMMC) */ - if (bus->dhd) { - dhdsdio_clkctl(bus, CLK_NONE, FALSE); - } - si_detach(bus->sih); - if (bus->vars && bus->varsz) - MFREE(osh, bus->vars, bus->varsz); - bus->vars = NULL; - } - - DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); -} - -static void -dhdsdio_disconnect(void *ptr) -{ - dhd_bus_t *bus = (dhd_bus_t *)ptr; - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - - if (mutex_is_locked(&_dhd_sdio_mutex_lock_) == 0) { - DHD_ERROR(("%s : no mutex held. set lock\n", __FUNCTION__)); - } - else { - DHD_ERROR(("%s : mutex is locked!. wait for unlocking\n", __FUNCTION__)); - } - mutex_lock(&_dhd_sdio_mutex_lock_); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ - - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - if (bus) { - ASSERT(bus->dhd); - dhdsdio_release(bus, bus->dhd->osh); - } - - DHD_TRACE(("%s: Disconnected\n", __FUNCTION__)); - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) - mutex_unlock(&_dhd_sdio_mutex_lock_); - DHD_ERROR(("%s : the lock is released.\n", __FUNCTION__)); -#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)) */ - -} - - -/* Register/Unregister functions are called by the main DHD entry - * point (e.g. module insertion) to link with the bus driver, in - * order to look for or await the device. - */ - -static bcmsdh_driver_t dhd_sdio = { - dhdsdio_probe, - dhdsdio_disconnect -}; - -int -dhd_bus_register(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - return bcmsdh_register(&dhd_sdio); -} - -void -dhd_bus_unregister(void) -{ - DHD_TRACE(("%s: Enter\n", __FUNCTION__)); - - bcmsdh_unregister(); -} - -#if defined(BCMLXSDMMC) -/* Register a dummy SDIO client driver in order to be notified of new SDIO device */ -int dhd_bus_reg_sdio_notify(void* semaphore) -{ - return bcmsdh_reg_sdio_notify(semaphore); -} - -void dhd_bus_unreg_sdio_notify(void) -{ - bcmsdh_unreg_sdio_notify(); -} -#endif /* defined(BCMLXSDMMC) */ - -#ifdef BCMEMBEDIMAGE -static int -dhdsdio_download_code_array(struct dhd_bus *bus) -{ - int bcmerror = -1; - int offset = 0; - unsigned char *ularray = NULL; - - DHD_INFO(("%s: download embedded firmware...\n", __FUNCTION__)); - - /* Download image */ - while ((offset + MEMBLOCK) < sizeof(dlarray)) { - bcmerror = dhdsdio_membytes(bus, TRUE, offset, - (uint8 *) (dlarray + offset), MEMBLOCK); - if (bcmerror) { - DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, MEMBLOCK, offset)); - goto err; - } - - offset += MEMBLOCK; - } - - if (offset < sizeof(dlarray)) { - bcmerror = dhdsdio_membytes(bus, TRUE, offset, - (uint8 *) (dlarray + offset), sizeof(dlarray) - offset); - if (bcmerror) { - DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); - goto err; - } - } - -#ifdef DHD_DEBUG - /* Upload and compare the downloaded code */ - { - ularray = MALLOC(bus->dhd->osh, bus->ramsize); - /* Upload image to verify downloaded contents. */ - offset = 0; - memset(ularray, 0xaa, bus->ramsize); - while ((offset + MEMBLOCK) < sizeof(dlarray)) { - bcmerror = dhdsdio_membytes(bus, FALSE, offset, ularray + offset, MEMBLOCK); - if (bcmerror) { - DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, MEMBLOCK, offset)); - goto err; - } - - offset += MEMBLOCK; - } - - if (offset < sizeof(dlarray)) { - bcmerror = dhdsdio_membytes(bus, FALSE, offset, - ularray + offset, sizeof(dlarray) - offset); - if (bcmerror) { - DHD_ERROR(("%s: error %d on reading %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, sizeof(dlarray) - offset, offset)); - goto err; - } - } - - if (memcmp(dlarray, ularray, sizeof(dlarray))) { - DHD_ERROR(("%s: Downloaded image is corrupted (%s, %s, %s).\n", - __FUNCTION__, dlimagename, dlimagever, dlimagedate)); - goto err; - } else - DHD_ERROR(("%s: Download, Upload and compare succeeded (%s, %s, %s).\n", - __FUNCTION__, dlimagename, dlimagever, dlimagedate)); - - } -#endif /* DHD_DEBUG */ - -err: - if (ularray) - MFREE(bus->dhd->osh, ularray, bus->ramsize); - return bcmerror; -} -#endif /* BCMEMBEDIMAGE */ - -static int -dhdsdio_download_code_file(struct dhd_bus *bus, char *pfw_path) -{ - int bcmerror = -1; - int offset = 0; - uint len; - void *image = NULL; - uint8 *memblock = NULL, *memptr; - - DHD_INFO(("%s: download firmware %s\n", __FUNCTION__, pfw_path)); - - image = dhd_os_open_image(pfw_path); - if (image == NULL) - goto err; - - memptr = memblock = MALLOC(bus->dhd->osh, MEMBLOCK + DHD_SDALIGN); - if (memblock == NULL) { - DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", __FUNCTION__, MEMBLOCK)); - goto err; - } - if ((uint32)(uintptr)memblock % DHD_SDALIGN) - memptr += (DHD_SDALIGN - ((uint32)(uintptr)memblock % DHD_SDALIGN)); - - /* Download image */ - while ((len = dhd_os_get_image_block((char*)memptr, MEMBLOCK, image))) { - bcmerror = dhdsdio_membytes(bus, TRUE, offset, memptr, len); - if (bcmerror) { - DHD_ERROR(("%s: error %d on writing %d membytes at 0x%08x\n", - __FUNCTION__, bcmerror, MEMBLOCK, offset)); - goto err; - } - - offset += MEMBLOCK; - } - -err: - if (memblock) - MFREE(bus->dhd->osh, memblock, MEMBLOCK + DHD_SDALIGN); - - if (image) - dhd_os_close_image(image); - - return bcmerror; -} - -/* - EXAMPLE: nvram_array - nvram_arry format: - name=value - Use carriage return at the end of each assignment, and an empty string with - carriage return at the end of array. - - For example: - unsigned char nvram_array[] = {"name1=value1\n", "name2=value2\n", "\n"}; - Hex values start with 0x, and mac addr format: xx:xx:xx:xx:xx:xx. - - Search "EXAMPLE: nvram_array" to see how the array is activated. -*/ - -void -dhd_bus_set_nvram_params(struct dhd_bus * bus, const char *nvram_params) -{ - bus->nvram_params = nvram_params; -} - -static int -dhdsdio_download_nvram(struct dhd_bus *bus) -{ - int bcmerror = -1; - uint len; - void * image = NULL; - char * memblock = NULL; - char *bufp; - char *pnv_path; - bool nvram_file_exists; - - pnv_path = bus->nv_path; - - nvram_file_exists = ((pnv_path != NULL) && (pnv_path[0] != '\0')); - if (!nvram_file_exists && (bus->nvram_params == NULL)) - return (0); - - if (nvram_file_exists) { - image = dhd_os_open_image(pnv_path); - if (image == NULL) - goto err; - } - - memblock = MALLOC(bus->dhd->osh, MAX_NVRAMBUF_SIZE); - if (memblock == NULL) { - DHD_ERROR(("%s: Failed to allocate memory %d bytes\n", - __FUNCTION__, MAX_NVRAMBUF_SIZE)); - goto err; - } - - /* Download variables */ - if (nvram_file_exists) { - len = dhd_os_get_image_block(memblock, MAX_NVRAMBUF_SIZE, image); - } - else { - len = strlen(bus->nvram_params); - ASSERT(len <= MAX_NVRAMBUF_SIZE); - memcpy(memblock, bus->nvram_params, len); - } - if (len > 0 && len < MAX_NVRAMBUF_SIZE) { - bufp = (char *)memblock; - bufp[len] = 0; - len = process_nvram_vars(bufp, len); - if (len % 4) { - len += 4 - (len % 4); - } - bufp += len; - *bufp++ = 0; - if (len) - bcmerror = dhdsdio_downloadvars(bus, memblock, len + 1); - if (bcmerror) { - DHD_ERROR(("%s: error downloading vars: %d\n", - __FUNCTION__, bcmerror)); - } - } - else { - DHD_ERROR(("%s: error reading nvram file: %d\n", - __FUNCTION__, len)); - bcmerror = BCME_SDIO_ERROR; - } - -err: - if (memblock) - MFREE(bus->dhd->osh, memblock, MAX_NVRAMBUF_SIZE); - - if (image) - dhd_os_close_image(image); - - return bcmerror; -} - -static int -_dhdsdio_download_firmware(struct dhd_bus *bus) -{ - int bcmerror = -1; - - bool embed = FALSE; /* download embedded firmware */ - bool dlok = FALSE; /* download firmware succeeded */ - - /* Out immediately if no image to download */ - if ((bus->fw_path == NULL) || (bus->fw_path[0] == '\0')) { -#ifdef BCMEMBEDIMAGE - embed = TRUE; -#else - return 0; -#endif - } - - /* Keep arm in reset */ - if (dhdsdio_download_state(bus, TRUE)) { - DHD_ERROR(("%s: error placing ARM core in reset\n", __FUNCTION__)); - goto err; - } - - /* External image takes precedence if specified */ - if ((bus->fw_path != NULL) && (bus->fw_path[0] != '\0')) { - if (dhdsdio_download_code_file(bus, bus->fw_path)) { - DHD_ERROR(("%s: dongle image file download failed\n", __FUNCTION__)); -#ifdef BCMEMBEDIMAGE - embed = TRUE; -#else - goto err; -#endif - } - else { - embed = FALSE; - dlok = TRUE; - } - } -#ifdef BCMEMBEDIMAGE - if (embed) { - if (dhdsdio_download_code_array(bus)) { - DHD_ERROR(("%s: dongle image array download failed\n", __FUNCTION__)); - goto err; - } - else { - dlok = TRUE; - } - } -#else - BCM_REFERENCE(embed); -#endif - if (!dlok) { - DHD_ERROR(("%s: dongle image download failed\n", __FUNCTION__)); - goto err; - } - - /* EXAMPLE: nvram_array */ - /* If a valid nvram_arry is specified as above, it can be passed down to dongle */ - /* dhd_bus_set_nvram_params(bus, (char *)&nvram_array); */ - - /* External nvram takes precedence if specified */ - if (dhdsdio_download_nvram(bus)) { - DHD_ERROR(("%s: dongle nvram file download failed\n", __FUNCTION__)); - goto err; - } - - /* Take arm out of reset */ - if (dhdsdio_download_state(bus, FALSE)) { - DHD_ERROR(("%s: error getting out of ARM core reset\n", __FUNCTION__)); - goto err; - } - - bcmerror = 0; - -err: - return bcmerror; -} - -static int -dhd_bcmsdh_recv_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, - void *pkt, bcmsdh_cmplt_fn_t complete, void *handle) -{ - int status; - - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - return BCME_NODEVICE; - } - - status = bcmsdh_recv_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle); - - return status; -} - -static int -dhd_bcmsdh_send_buf(dhd_bus_t *bus, uint32 addr, uint fn, uint flags, uint8 *buf, uint nbytes, - void *pkt, bcmsdh_cmplt_fn_t complete, void *handle) -{ - if (!KSO_ENAB(bus)) { - DHD_ERROR(("%s: Device asleep\n", __FUNCTION__)); - return BCME_NODEVICE; - } - - return (bcmsdh_send_buf(bus->sdh, addr, fn, flags, buf, nbytes, pkt, complete, handle)); -} - -uint -dhd_bus_chip(struct dhd_bus *bus) -{ - ASSERT(bus->sih != NULL); - return bus->sih->chip; -} - -void * -dhd_bus_pub(struct dhd_bus *bus) -{ - return bus->dhd; -} - -void * -dhd_bus_txq(struct dhd_bus *bus) -{ - return &bus->txq; -} - -uint -dhd_bus_hdrlen(struct dhd_bus *bus) -{ - return SDPCM_HDRLEN; -} - -int -dhd_bus_devreset(dhd_pub_t *dhdp, uint8 flag) -{ - int bcmerror = 0; - dhd_bus_t *bus; - - bus = dhdp->bus; - - if (flag == TRUE) { - if (!bus->dhd->dongle_reset) { - dhd_os_sdlock(dhdp); - dhd_os_wd_timer(dhdp, 0); -#if !defined(IGNORE_ETH0_DOWN) - /* Force flow control as protection when stop come before ifconfig_down */ - dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, ON); -#endif /* !defined(IGNORE_ETH0_DOWN) */ - /* Expect app to have torn down any connection before calling */ - /* Stop the bus, disable F2 */ - dhd_bus_stop(bus, FALSE); - -#if defined(OOB_INTR_ONLY) - /* Clean up any pending IRQ */ - bcmsdh_set_irq(FALSE); -#endif /* defined(OOB_INTR_ONLY) */ - - /* Clean tx/rx buffer pointers, detach from the dongle */ - dhdsdio_release_dongle(bus, bus->dhd->osh, TRUE, TRUE); - - bus->dhd->dongle_reset = TRUE; - bus->dhd->up = FALSE; - dhd_os_sdunlock(dhdp); - - DHD_TRACE(("%s: WLAN OFF DONE\n", __FUNCTION__)); - /* App can now remove power from device */ - } else - bcmerror = BCME_SDIO_ERROR; - } else { - /* App must have restored power to device before calling */ - - DHD_TRACE(("\n\n%s: == WLAN ON ==\n", __FUNCTION__)); - - if (bus->dhd->dongle_reset) { - /* Turn on WLAN */ -#ifdef DHDTHREAD - dhd_os_sdlock(dhdp); -#endif /* DHDTHREAD */ - /* Reset SD client */ - bcmsdh_reset(bus->sdh); - - /* Attempt to re-attach & download */ - if (dhdsdio_probe_attach(bus, bus->dhd->osh, bus->sdh, - (uint32 *)SI_ENUM_BASE, - bus->cl_devid)) { - /* Attempt to download binary to the dongle */ - if (dhdsdio_probe_init(bus, bus->dhd->osh, bus->sdh) && - dhdsdio_download_firmware(bus, bus->dhd->osh, bus->sdh)) { - - /* Re-init bus, enable F2 transfer */ - bcmerror = dhd_bus_init((dhd_pub_t *) bus->dhd, FALSE); - if (bcmerror == BCME_OK) { -#if defined(OOB_INTR_ONLY) - bcmsdh_set_irq(TRUE); - dhd_enable_oob_intr(bus, TRUE); -#endif /* defined(OOB_INTR_ONLY) */ - - bus->dhd->dongle_reset = FALSE; - bus->dhd->up = TRUE; - -#if !defined(IGNORE_ETH0_DOWN) - /* Restore flow control */ - dhd_txflowcontrol(bus->dhd, ALL_INTERFACES, OFF); -#endif - dhd_os_wd_timer(dhdp, dhd_watchdog_ms); - - DHD_TRACE(("%s: WLAN ON DONE\n", __FUNCTION__)); - } else { - dhd_bus_stop(bus, FALSE); - dhdsdio_release_dongle(bus, bus->dhd->osh, - TRUE, FALSE); - } - } else - bcmerror = BCME_SDIO_ERROR; - } else - bcmerror = BCME_SDIO_ERROR; - -#ifdef DHDTHREAD - dhd_os_sdunlock(dhdp); -#endif /* DHDTHREAD */ - } else { - bcmerror = BCME_SDIO_ERROR; - DHD_INFO(("%s called when dongle is not in reset\n", - __FUNCTION__)); - DHD_INFO(("Will call dhd_bus_start instead\n")); - sdioh_start(NULL, 1); - if ((bcmerror = dhd_bus_start(dhdp)) != 0) - DHD_ERROR(("%s: dhd_bus_start fail with %d\n", - __FUNCTION__, bcmerror)); - } - } - return bcmerror; -} - -int -dhd_bus_membytes(dhd_pub_t *dhdp, bool set, uint32 address, uint8 *data, uint size) -{ - dhd_bus_t *bus; - - bus = dhdp->bus; - return dhdsdio_membytes(bus, set, address, data, size); -} diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sec_feature.h b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sec_feature.h deleted file mode 100644 index d6bb7f0..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_sec_feature.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Header file describing the internal (inter-module) DHD interfaces. - * - * Provides type definitions and function prototypes used to link the - * DHD OS, bus, and protocol modules. - * - * Copyright (C) 1999-2012, Broadcom Corporation - * - * Unless you and Broadcom execute a separate written software license - * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2 (the "GPL"), - * available at http://www.broadcom.com/licenses/GPLv2.php, with the - * following added to such license: - * - * As a special exception, the copyright holders of this software give you - * permission to link this software with independent modules, and to copy and - * distribute the resulting executable under terms of your choice, provided that - * you also meet, for each linked independent module, the terms and conditions of - * the license of that module. An independent module is a module which is not - * derived from this software. The special exception does not apply to any - * modifications of the software. - * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a license - * other than the GPL, without Broadcom's express prior written consent. - * - * $Id: dhd_sec_feature.h 309548 2012-01-20 01:13:08Z $ - */ - -#ifdef USE_SECFEATURE -#include <sec_feature/GlobalConfig.h> -#include <sec_feature/CustFeature.h> -#endif - -/* PROJECTS */ - -#if defined(CONFIG_MACH_SAMSUNG_ESPRESSO)\ - || defined(CONFIG_MACH_SAMSUNG_ESPRESSO_10) -#define READ_MACADDR -#define HW_OOB -#endif - -/* Q1 also uses this feature */ -#if defined(CONFIG_MACH_U1) || defined(CONFIG_MACH_TRATS) -#ifdef CONFIG_MACH_Q1_BD -#define HW_OOB -#endif -#define USE_CID_CHECK -#define WRITE_MACADDR -#endif - -#ifdef CONFIG_ARCH_MSM7X30 -#define HW_OOB -#define READ_MACADDR -#endif - -#ifdef CONFIG_MACH_GC1 -#undef USE_CID_CHECK -#define READ_MACADDR -#endif - -#ifdef CONFIG_MACH_P10 -#define READ_MACADDR -#endif - -/* REGION CODE */ - -#if (WLAN_REGION_CODE >= 100) && (WLAN_REGION_CODE < 200) /*EUR*/ -#if (WLAN_REGION_CODE == 101) /*EUR ORG*/ -;/* GAN LITE NAT KEEPALIVE FILTER */ -#define GAN_LITE_NAT_KEEPALIVE_FILTER -#endif -#endif - -#if (WLAN_REGION_CODE >= 200) && (WLAN_REGION_CODE < 300) /* KOR */ -#undef USE_INITIAL_2G_SCAN_ORG -#ifndef ROAM_ENABLE -#define ROAM_ENABLE -#endif -#ifndef ROAM_API -#define ROAM_API -#endif -#ifndef ROAM_CHANNEL_CACHE -#define ROAM_CHANNEL_CACHE -#endif -#ifndef OKC_SUPPORT -#define OKC_SUPPORT -#endif - -/* for debug */ -#ifdef RSSI_OFFSET -#undef RSSI_OFFSET -#define RSSI_OFFSET 8 -#else -#define RSSI_OFFSET 8 -#endif - -#undef WRITE_MACADDR -#undef READ_MACADDR -#ifdef CONFIG_BCM4334 -#define READ_MACADDR -#else -#define RDWR_MACADDR -#endif - -#if (WLAN_REGION_CODE == 201) /* SKT */ -#endif - -#if (WLAN_REGION_CODE == 202) /* KTT */ -#define VLAN_MODE_OFF -#define KEEP_ALIVE_PACKET_PERIOD_30_SEC -#define FULL_ROAMING_SCAN_PERIOD_60_SEC -#endif - -#if (WLAN_REGION_CODE == 203) /* LGT */ -#endif -#endif - -#if (WLAN_REGION_CODE >= 300) && (WLAN_REGION_CODE < 400) /* CHN */ -#define BCMWAPI_WPI -#define BCMWAPI_WAI -#endif - -#if !defined(READ_MACADDR) && !defined(WRITE_MACADDR) && !defined(RDWR_KORICS_MACADDR) && !defined(RDWR_MACADDR) -#define GET_MAC_FROM_OTP -#endif - diff --git a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_wlfc.h b/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_wlfc.h deleted file mode 100644 index 308e318..0000000 --- a/drivers/net/wireless/bcmdhd/src/dhd/sys/dhd_wlfc.h +++ /dev/null @@ -1,284 +0,0 @@ -/* -* Copyright (C) 1999-2011, Broadcom Corporation -* -* Unless you and Broadcom execute a separate written software license -* agreement governing use of this software, this software is licensed to you -* under the terms of the GNU General Public License version 2 (the "GPL"), -* available at http://www.broadcom.com/licenses/GPLv2.php, with the -* following added to such license: -* -* As a special exception, the copyright holders of this software give you -* permission to link this software with independent modules, and to copy and -* distribute the resulting executable under terms of your choice, provided that -* you also meet, for each linked independent module, the terms and conditions of -* the license of that module. An independent module is a module which is not -* derived from this software. The special exception does not apply to any -* modifications of the software. -* -* Notwithstanding the above, under no circumstances may you combine this -* software in any way with any other Broadcom software provided under a license -* other than the GPL, without Broadcom's express prior written consent. -* $Id: dhd_wlfc.h 294267 2011-11-04 23:41:52Z $ -* -*/ -#ifndef __wlfc_host_driver_definitions_h__ -#define __wlfc_host_driver_definitions_h__ - -/* 16 bits will provide an absolute max of 65536 slots */ -#define WLFC_HANGER_MAXITEMS 1024 - -#define WLFC_HANGER_ITEM_STATE_FREE 1 -#define WLFC_HANGER_ITEM_STATE_INUSE 2 -#define WLFC_HANGER_ITEM_STATE_INUSE_SUPPRESSED 3 - -#define WLFC_PKTID_HSLOT_MASK 0xffff /* allow 16 bits only */ -#define WLFC_PKTID_HSLOT_SHIFT 8 - -/* x -> TXSTATUS TAG to/from firmware */ -#define WLFC_PKTID_HSLOT_GET(x) \ - (((x) >> WLFC_PKTID_HSLOT_SHIFT) & WLFC_PKTID_HSLOT_MASK) -#define WLFC_PKTID_HSLOT_SET(var, slot) \ - ((var) = ((var) & ~(WLFC_PKTID_HSLOT_MASK << WLFC_PKTID_HSLOT_SHIFT)) | \ - (((slot) & WLFC_PKTID_HSLOT_MASK) << WLFC_PKTID_HSLOT_SHIFT)) - -#define WLFC_PKTID_FREERUNCTR_MASK 0xff - -#define WLFC_PKTID_FREERUNCTR_GET(x) ((x) & WLFC_PKTID_FREERUNCTR_MASK) -#define WLFC_PKTID_FREERUNCTR_SET(var, ctr) \ - ((var) = (((var) & ~WLFC_PKTID_FREERUNCTR_MASK) | \ - (((ctr) & WLFC_PKTID_FREERUNCTR_MASK)))) - -#define WLFC_PKTQ_PENQ(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec)))? \ - NULL : pktq_penq((pq), (prec), (p))) -#define WLFC_PKTQ_PENQ_HEAD(pq, prec, p) ((pktq_full((pq)) || pktq_pfull((pq), (prec))) ? \ - NULL : pktq_penq_head((pq), (prec), (p))) - -typedef enum ewlfc_packet_state { - eWLFC_PKTTYPE_NEW, - eWLFC_PKTTYPE_DELAYED, - eWLFC_PKTTYPE_SUPPRESSED, - eWLFC_PKTTYPE_MAX -} ewlfc_packet_state_t; - -typedef enum ewlfc_mac_entry_action { - eWLFC_MAC_ENTRY_ACTION_ADD, - eWLFC_MAC_ENTRY_ACTION_DEL, - eWLFC_MAC_ENTRY_ACTION_UPDATE, - eWLFC_MAC_ENTRY_ACTION_MAX -} ewlfc_mac_entry_action_t; - -typedef struct wlfc_hanger_item { - uint8 state; - uint8 gen; - uint8 pad[2]; - uint32 identifier; - void* pkt; -#ifdef PROP_TXSTATUS_DEBUG - uint32 push_time; -#endif -} wlfc_hanger_item_t; - -typedef struct wlfc_hanger { - int max_items; - uint32 pushed; - uint32 popped; - uint32 failed_to_push; - uint32 failed_to_pop; - uint32 failed_slotfind; - wlfc_hanger_item_t items[1]; -} wlfc_hanger_t; - -#define WLFC_HANGER_SIZE(n) ((sizeof(wlfc_hanger_t) - \ - sizeof(wlfc_hanger_item_t)) + ((n)*sizeof(wlfc_hanger_item_t))) - -#define WLFC_STATE_OPEN 1 -#define WLFC_STATE_CLOSE 2 - -#define WLFC_PSQ_PREC_COUNT ((AC_COUNT + 1) * 2) /* 2 for each AC traffic and bc/mc */ -#define WLFC_PSQ_LEN 2048 -#define WLFC_SENDQ_LEN 256 /* XXX: Match dhd_sdio txq length */ - -#define WLFC_FLOWCONTROL_HIWATER (2048 - 256) -#define WLFC_FLOWCONTROL_LOWATER 256 - - -typedef struct wlfc_mac_descriptor { - uint8 occupied; - uint8 interface_id; - uint8 iftype; - uint8 state; - uint8 ac_bitmap; /* for APSD */ - uint8 requested_credit; - uint8 requested_packet; - uint8 ea[ETHER_ADDR_LEN]; - /* - maintain (MAC,AC) based seq count for - packets going to the device. As well as bc/mc. - */ - uint8 seq[AC_COUNT + 1]; - uint8 generation; - struct pktq psq; - /* The AC pending bitmap that was reported to the fw at last change */ - uint8 traffic_lastreported_bmp; - /* The new AC pending bitmap */ - uint8 traffic_pending_bmp; - /* 1= send on next opportunity */ - uint8 send_tim_signal; - uint8 mac_handle; - uint transit_count; - uint suppr_transit_count; - uint suppress_count; - uint8 suppressed; - -#ifdef PROP_TXSTATUS_DEBUG - uint32 dstncredit_sent_packets; - uint32 dstncredit_acks; - uint32 opened_ct; - uint32 closed_ct; -#endif -} wlfc_mac_descriptor_t; - -#define WLFC_DECR_SEQCOUNT(entry, prec) do { if (entry->seq[(prec)] == 0) {\ - entry->seq[prec] = 0xff; } else entry->seq[prec]--;} while (0) - -#define WLFC_INCR_SEQCOUNT(entry, prec) entry->seq[(prec)]++ -#define WLFC_SEQCOUNT(entry, prec) entry->seq[(prec)] - -typedef struct athost_wl_stat_counters { - uint32 pktin; - uint32 pkt2bus; - uint32 pktdropped; - uint32 tlv_parse_failed; - uint32 rollback; - uint32 rollback_failed; - uint32 sendq_full_error; - uint32 delayq_full_error; - uint32 credit_request_failed; - uint32 packet_request_failed; - uint32 mac_update_failed; - uint32 psmode_update_failed; - uint32 interface_update_failed; - uint32 wlfc_header_only_pkt; - uint32 txstatus_in; - uint32 d11_suppress; - uint32 wl_suppress; - uint32 bad_suppress; - uint32 pkt_freed; - uint32 pkt_free_err; - uint32 psq_wlsup_retx; - uint32 psq_wlsup_enq; - uint32 psq_d11sup_retx; - uint32 psq_d11sup_enq; - uint32 psq_hostq_retx; - uint32 psq_hostq_enq; - uint32 mac_handle_notfound; - uint32 wlc_tossed_pkts; - uint32 dhd_hdrpulls; - uint32 generic_error; - /* an extra one for bc/mc traffic */ - uint32 sendq_pkts[AC_COUNT + 1]; -#ifdef PROP_TXSTATUS_DEBUG - /* all pkt2bus -> txstatus latency accumulated */ - uint32 latency_sample_count; - uint32 total_status_latency; - uint32 latency_most_recent; - int idx_delta; - uint32 deltas[10]; - uint32 fifo_credits_sent[6]; - uint32 fifo_credits_back[6]; - uint32 dropped_qfull[6]; - uint32 signal_only_pkts_sent; - uint32 signal_only_pkts_freed; -#endif -} athost_wl_stat_counters_t; - -#ifdef PROP_TXSTATUS_DEBUG -#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do { \ - (ctx)->stats.fifo_credits_sent[(ac)]++;} while (0) -#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do { \ - (ctx)->stats.fifo_credits_back[(ac)]++;} while (0) -#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do { \ - (ctx)->stats.dropped_qfull[(ac)]++;} while (0) -#else -#define WLFC_HOST_FIFO_CREDIT_INC_SENTCTRS(ctx, ac) do {} while (0) -#define WLFC_HOST_FIFO_CREDIT_INC_BACKCTRS(ctx, ac) do {} while (0) -#define WLFC_HOST_FIFO_DROPPEDCTR_INC(ctx, ac) do {} while (0) -#endif - -#define WLFC_FCMODE_NONE 0 -#define WLFC_FCMODE_IMPLIED_CREDIT 1 -#define WLFC_FCMODE_EXPLICIT_CREDIT 2 - -/* How long to defer borrowing in milliseconds */ -#define WLFC_BORROW_DEFER_PERIOD_MS 100 - -/* Mask to represent available ACs (note: BC/MC is ignored */ -#define WLFC_AC_MASK 0xF - -/* Mask to check for only on-going AC_BE traffic */ -#define WLFC_AC_BE_TRAFFIC_ONLY 0xD - -typedef struct athost_wl_status_info { - uint8 last_seqid_to_wlc; - - /* OSL handle */ - osl_t* osh; - /* dhd pub */ - void* dhdp; - - /* stats */ - athost_wl_stat_counters_t stats; - - /* the additional ones are for bc/mc and ATIM FIFO */ - int FIFO_credit[AC_COUNT + 2]; - - /* Credit borrow counts for each FIFO from each of the other FIFOs */ - int credits_borrowed[AC_COUNT + 2][AC_COUNT + 2]; - - struct pktq SENDQ; - - /* packet hanger and MAC->handle lookup table */ - void* hanger; - struct { - /* table for individual nodes */ - wlfc_mac_descriptor_t nodes[WLFC_MAC_DESC_TABLE_SIZE]; - /* table for interfaces */ - wlfc_mac_descriptor_t interfaces[WLFC_MAX_IFNUM]; - /* OS may send packets to unknown (unassociated) destinations */ - /* A place holder for bc/mc and packets to unknown destinations */ - wlfc_mac_descriptor_t other; - } destination_entries; - /* token position for different priority packets */ - uint8 token_pos[AC_COUNT+1]; - /* ON/OFF state for flow control to the host network interface */ - uint8 hostif_flow_state[WLFC_MAX_IFNUM]; - uint8 host_ifidx; - /* to flow control an OS interface */ - uint8 toggle_host_if; - - /* - Mode in which the dhd flow control shall operate. Must be set before - traffic starts to the device. - 0 - Do not do any proptxtstatus flow control - 1 - Use implied credit from a packet status - 2 - Use explicit credit - */ - uint8 proptxstatus_mode; - - /* To borrow credits */ - uint8 allow_credit_borrow; - - /* Timestamp to compute how long to defer borrowing for */ - uint32 borrow_defer_timestamp; - -} athost_wl_status_info_t; - -int dhd_wlfc_enable(dhd_pub_t *dhd); -int dhd_wlfc_interface_event(struct dhd_info *, - ewlfc_mac_entry_action_t action, uint8 ifid, uint8 iftype, uint8* ea); -int dhd_wlfc_FIFOcreditmap_event(struct dhd_info *dhd, uint8* event_data); -int dhd_wlfc_event(struct dhd_info *dhd); -int dhd_os_wlfc_block(dhd_pub_t *pub); -int dhd_os_wlfc_unblock(dhd_pub_t *pub); - -#endif /* __wlfc_host_driver_definitions_h__ */ |